Upgrade our copy of clang, llvm and lldb to 3.5.0 release.
Please note that this version now requires C++11 support to build; see UPDATING for more information. Release notes for llvm and clang can be found here: <http://llvm.org/releases/3.5.0/docs/ReleaseNotes.html> <http://llvm.org/releases/3.5.0/tools/clang/docs/ReleaseNotes.html> Thanks to Ed Maste, Roman Divacky, Andrew Turner, Justin Hibbits and Antoine Brodin for their invaluable help with this import. Approved by: portmgr (antoine) MFC after: 1 month
This commit is contained in:
commit
44b6c81fe4
@ -38,6 +38,42 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20141231: new clang import which bumps version from 3.4.1 to 3.5.0.
|
||||
OLD_FILES+=usr/include/clang/3.4.1/__wmmintrin_aes.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/__wmmintrin_pclmul.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/altivec.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/ammintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/arm_neon.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/avx2intrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/avxintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/bmi2intrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/bmiintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/cpuid.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/emmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/f16cintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/fma4intrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/fmaintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/immintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/lzcntintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/mm3dnow.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/mm_malloc.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/mmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/module.map
|
||||
OLD_FILES+=usr/include/clang/3.4.1/nmmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/pmmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/popcntintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/prfchwintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/rdseedintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/rtmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/shaintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/smmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/tbmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/tmmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/wmmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/x86intrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/xmmintrin.h
|
||||
OLD_FILES+=usr/include/clang/3.4.1/xopintrin.h
|
||||
OLD_DIRS+=usr/include/clang/3.4.1
|
||||
# 20141226: Remove gpib/ieee488
|
||||
OLD_FILES+=usr/include/dev/ieee488/ibfoo_int.h
|
||||
OLD_FILES+=usr/include/dev/ieee488/tnt4882.h
|
||||
|
62
UPDATING
62
UPDATING
@ -31,6 +31,68 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW:
|
||||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20141231:
|
||||
Clang, llvm and lldb have been upgraded to 3.5.0 release.
|
||||
|
||||
As of this release, a prerequisite for building clang, llvm and lldb is
|
||||
a C++11 capable compiler and C++11 standard library. This means that to
|
||||
be able to successfully build the cross-tools stage of buildworld, with
|
||||
clang as the bootstrap compiler, your system compiler or cross compiler
|
||||
should either be clang 3.3 or later, or gcc 4.8 or later, and your
|
||||
system C++ library should be libc++, or libdstdc++ from gcc 4.8 or
|
||||
later.
|
||||
|
||||
On any standard FreeBSD 10.x or 11.x installation, where clang and
|
||||
libc++ are on by default (that is, on x86 or arm), this should work out
|
||||
of the box.
|
||||
|
||||
On 9.x installations where clang is enabled by default, e.g. on x86 and
|
||||
powerpc, libc++ will not be enabled by default, so libc++ should be
|
||||
built (with clang) and installed first. If both clang and libc++ are
|
||||
missing, build clang first, then use it to build libc++.
|
||||
|
||||
On 8.x and earlier installations, upgrade to 9.x first, and then follow
|
||||
the instructions for 9.x above.
|
||||
|
||||
Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by
|
||||
default, and do not build clang.
|
||||
|
||||
Many embedded systems are resource constrained, and will not be able to
|
||||
build clang in a reasonable time, or in some cases at all. In those
|
||||
cases, cross building bootable systems on amd64 is a workaround.
|
||||
|
||||
This new version of clang introduces a number of new warnings, of which
|
||||
the following are most likely to appear:
|
||||
|
||||
-Wabsolute-value
|
||||
|
||||
This warns in two cases, for both C and C++:
|
||||
* When the code is trying to take the absolute value of an unsigned
|
||||
quantity, which is effectively a no-op, and almost never what was
|
||||
intended. The code should be fixed, if at all possible. If you are
|
||||
sure that the unsigned quantity can be safely cast to signed, without
|
||||
loss of information or undefined behavior, you can add an explicit
|
||||
cast, or disable the warning.
|
||||
|
||||
* When the code is trying to take an absolute value, but the called
|
||||
abs() variant is for the wrong type, which can lead to truncation.
|
||||
If you want to disable the warning instead of fixing the code, please
|
||||
make sure that truncation will not occur, or it might lead to unwanted
|
||||
side-effects.
|
||||
|
||||
-Wtautological-undefined-compare and
|
||||
-Wundefined-bool-conversion
|
||||
|
||||
These warn when C++ code is trying to compare 'this' against NULL, while
|
||||
'this' should never be NULL in well-defined C++ code. However, there is
|
||||
some legacy (pre C++11) code out there, which actively abuses this
|
||||
feature, which was less strictly defined in previous C++ versions.
|
||||
|
||||
Squid and openjdk do this, for example. The warning can be turned off
|
||||
for C++98 and earlier, but compiling the code in C++11 mode might result
|
||||
in unexpected behavior; for example, the parts of the program that are
|
||||
unreachable could be optimized away.
|
||||
|
||||
20141222:
|
||||
The old NFS client and server (kernel options NFSCLIENT, NFSSERVER)
|
||||
kernel sources have been removed. The .h files remain, since some
|
||||
|
@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2013 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
@ -63,7 +63,6 @@ Program Directory
|
||||
------- ---------
|
||||
Autoconf llvm/autoconf
|
||||
llvm/projects/ModuleMaker/autoconf
|
||||
llvm/projects/sample/autoconf
|
||||
Google Test llvm/utils/unittest/googletest
|
||||
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
|
||||
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifndef LLVM_C_CORE_H
|
||||
#define LLVM_C_CORE_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm-c/Support.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -62,8 +62,6 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef int LLVMBool;
|
||||
|
||||
/* Opaque types. */
|
||||
|
||||
/**
|
||||
@ -114,13 +112,6 @@ typedef struct LLVMOpaqueBuilder *LLVMBuilderRef;
|
||||
*/
|
||||
typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef;
|
||||
|
||||
/**
|
||||
* Used to provide a module to JIT or interpreter.
|
||||
*
|
||||
* @see llvm::MemoryBuffer
|
||||
*/
|
||||
typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef;
|
||||
|
||||
/** @see llvm::PassManagerBase */
|
||||
typedef struct LLVMOpaquePassManager *LLVMPassManagerRef;
|
||||
|
||||
@ -133,6 +124,12 @@ typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef;
|
||||
* @see llvm::Use */
|
||||
typedef struct LLVMOpaqueUse *LLVMUseRef;
|
||||
|
||||
|
||||
/**
|
||||
* @see llvm::DiagnosticInfo
|
||||
*/
|
||||
typedef struct LLVMOpaqueDiagnosticInfo *LLVMDiagnosticInfoRef;
|
||||
|
||||
typedef enum {
|
||||
LLVMZExtAttribute = 1<<0,
|
||||
LLVMSExtAttribute = 1<<1,
|
||||
@ -167,7 +164,11 @@ typedef enum {
|
||||
LLVMAddressSafety = 1ULL << 32,
|
||||
LLVMStackProtectStrongAttribute = 1ULL<<33,
|
||||
LLVMCold = 1ULL << 34,
|
||||
LLVMOptimizeNone = 1ULL << 35
|
||||
LLVMOptimizeNone = 1ULL << 35,
|
||||
LLVMInAllocaAttribute = 1ULL << 36,
|
||||
LLVMNonNullAttribute = 1ULL << 37,
|
||||
LLVMJumpTableAttribute = 1ULL << 38,
|
||||
LLVMDereferenceableAttribute = 1ULL << 39,
|
||||
*/
|
||||
} LLVMAttribute;
|
||||
|
||||
@ -283,8 +284,8 @@ typedef enum {
|
||||
LLVMInternalLinkage, /**< Rename collisions when linking (static
|
||||
functions) */
|
||||
LLVMPrivateLinkage, /**< Like Internal, but omit from symbol table */
|
||||
LLVMDLLImportLinkage, /**< Function to be imported from DLL */
|
||||
LLVMDLLExportLinkage, /**< Function to be accessible from DLL */
|
||||
LLVMDLLImportLinkage, /**< Obsolete */
|
||||
LLVMDLLExportLinkage, /**< Obsolete */
|
||||
LLVMExternalWeakLinkage,/**< ExternalWeak linkage description */
|
||||
LLVMGhostLinkage, /**< Obsolete */
|
||||
LLVMCommonLinkage, /**< Tentative definitions */
|
||||
@ -298,6 +299,12 @@ typedef enum {
|
||||
LLVMProtectedVisibility /**< The GV is protected */
|
||||
} LLVMVisibility;
|
||||
|
||||
typedef enum {
|
||||
LLVMDefaultStorageClass = 0,
|
||||
LLVMDLLImportStorageClass = 1, /**< Function to be imported from DLL. */
|
||||
LLVMDLLExportStorageClass = 2 /**< Function to be accessible from DLL. */
|
||||
} LLVMDLLStorageClass;
|
||||
|
||||
typedef enum {
|
||||
LLVMCCallConv = 0,
|
||||
LLVMFastCallConv = 8,
|
||||
@ -402,6 +409,13 @@ typedef enum {
|
||||
the old one */
|
||||
} LLVMAtomicRMWBinOp;
|
||||
|
||||
typedef enum {
|
||||
LLVMDSError,
|
||||
LLVMDSWarning,
|
||||
LLVMDSRemark,
|
||||
LLVMDSNote
|
||||
} LLVMDiagnosticSeverity;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -455,6 +469,9 @@ void LLVMEnablePrettyStackTrace(void);
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef void (*LLVMDiagnosticHandler)(LLVMDiagnosticInfoRef, void *);
|
||||
typedef void (*LLVMYieldCallback)(LLVMContextRef, void *);
|
||||
|
||||
/**
|
||||
* Create a new context.
|
||||
*
|
||||
@ -468,6 +485,21 @@ LLVMContextRef LLVMContextCreate(void);
|
||||
*/
|
||||
LLVMContextRef LLVMGetGlobalContext(void);
|
||||
|
||||
/**
|
||||
* Set the diagnostic handler for this context.
|
||||
*/
|
||||
void LLVMContextSetDiagnosticHandler(LLVMContextRef C,
|
||||
LLVMDiagnosticHandler Handler,
|
||||
void *DiagnosticContext);
|
||||
|
||||
/**
|
||||
* Set the yield callback function for this context.
|
||||
*
|
||||
* @see LLVMContext::setYieldCallback()
|
||||
*/
|
||||
void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,
|
||||
void *OpaqueHandle);
|
||||
|
||||
/**
|
||||
* Destroy a context instance.
|
||||
*
|
||||
@ -476,6 +508,21 @@ LLVMContextRef LLVMGetGlobalContext(void);
|
||||
*/
|
||||
void LLVMContextDispose(LLVMContextRef C);
|
||||
|
||||
/**
|
||||
* Return a string representation of the DiagnosticInfo. Use
|
||||
* LLVMDisposeMessage to free the string.
|
||||
*
|
||||
* @see DiagnosticInfo::print()
|
||||
*/
|
||||
char *LLVMGetDiagInfoDescription(LLVMDiagnosticInfoRef DI);
|
||||
|
||||
/**
|
||||
* Return an enum LLVMDiagnosticSeverity.
|
||||
*
|
||||
* @see DiagnosticInfo::getSeverity()
|
||||
*/
|
||||
LLVMDiagnosticSeverity LLVMGetDiagInfoSeverity(LLVMDiagnosticInfoRef DI);
|
||||
|
||||
unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char* Name,
|
||||
unsigned SLen);
|
||||
unsigned LLVMGetMDKindID(const char* Name, unsigned SLen);
|
||||
@ -1123,9 +1170,10 @@ LLVMTypeRef LLVMX86MMXType(void);
|
||||
macro(ConstantStruct) \
|
||||
macro(ConstantVector) \
|
||||
macro(GlobalValue) \
|
||||
macro(Function) \
|
||||
macro(GlobalAlias) \
|
||||
macro(GlobalVariable) \
|
||||
macro(GlobalObject) \
|
||||
macro(Function) \
|
||||
macro(GlobalVariable) \
|
||||
macro(UndefValue) \
|
||||
macro(Instruction) \
|
||||
macro(BinaryOperator) \
|
||||
@ -1688,6 +1736,10 @@ const char *LLVMGetSection(LLVMValueRef Global);
|
||||
void LLVMSetSection(LLVMValueRef Global, const char *Section);
|
||||
LLVMVisibility LLVMGetVisibility(LLVMValueRef Global);
|
||||
void LLVMSetVisibility(LLVMValueRef Global, LLVMVisibility Viz);
|
||||
LLVMDLLStorageClass LLVMGetDLLStorageClass(LLVMValueRef Global);
|
||||
void LLVMSetDLLStorageClass(LLVMValueRef Global, LLVMDLLStorageClass Class);
|
||||
LLVMBool LLVMHasUnnamedAddr(LLVMValueRef Global);
|
||||
void LLVMSetUnnamedAddr(LLVMValueRef Global, LLVMBool HasUnnamedAddr);
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCCoreValueWithAlignment Values with alignment
|
||||
@ -1698,6 +1750,7 @@ void LLVMSetVisibility(LLVMValueRef Global, LLVMVisibility Viz);
|
||||
|
||||
/**
|
||||
* Obtain the preferred alignment of the value.
|
||||
* @see llvm::AllocaInst::getAlignment()
|
||||
* @see llvm::LoadInst::getAlignment()
|
||||
* @see llvm::StoreInst::getAlignment()
|
||||
* @see llvm::GlobalValue::getAlignment()
|
||||
@ -1706,6 +1759,7 @@ unsigned LLVMGetAlignment(LLVMValueRef V);
|
||||
|
||||
/**
|
||||
* Set the preferred alignment of the value.
|
||||
* @see llvm::AllocaInst::setAlignment()
|
||||
* @see llvm::LoadInst::setAlignment()
|
||||
* @see llvm::StoreInst::setAlignment()
|
||||
* @see llvm::GlobalValue::setAlignment()
|
||||
@ -2663,7 +2717,9 @@ LLVMValueRef LLVMBuildIsNotNull(LLVMBuilderRef, LLVMValueRef Val,
|
||||
const char *Name);
|
||||
LLVMValueRef LLVMBuildPtrDiff(LLVMBuilderRef, LLVMValueRef LHS,
|
||||
LLVMValueRef RHS, const char *Name);
|
||||
LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B,LLVMAtomicRMWBinOp op,
|
||||
LLVMValueRef LLVMBuildFence(LLVMBuilderRef B, LLVMAtomicOrdering ordering,
|
||||
LLVMBool singleThread, const char *Name);
|
||||
LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, LLVMAtomicRMWBinOp op,
|
||||
LLVMValueRef PTR, LLVMValueRef Val,
|
||||
LLVMAtomicOrdering ordering,
|
||||
LLVMBool singleThread);
|
||||
@ -2793,16 +2849,13 @@ void LLVMDisposePassManager(LLVMPassManagerRef PM);
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Allocate and initialize structures needed to make LLVM safe for
|
||||
multithreading. The return value indicates whether multithreaded
|
||||
initialization succeeded. Must be executed in isolation from all
|
||||
other LLVM api calls.
|
||||
@see llvm::llvm_start_multithreaded */
|
||||
/** Deprecated: Multi-threading can only be enabled/disabled with the compile
|
||||
time define LLVM_ENABLE_THREADS. This function always returns
|
||||
LLVMIsMultithreaded(). */
|
||||
LLVMBool LLVMStartMultithreaded(void);
|
||||
|
||||
/** Deallocate structures necessary to make LLVM safe for multithreading.
|
||||
Must be executed in isolation from all other LLVM api calls.
|
||||
@see llvm::llvm_stop_multithreaded */
|
||||
/** Deprecated: Multi-threading can only be enabled/disabled with the compile
|
||||
time define LLVM_ENABLE_THREADS. */
|
||||
void LLVMStopMultithreaded(void);
|
||||
|
||||
/** Check whether LLVM is executing in thread-safe mode or not.
|
||||
|
@ -95,6 +95,16 @@ struct LLVMOpInfo1 {
|
||||
#define LLVMDisassembler_VariantKind_ARM_HI16 1 /* :upper16: */
|
||||
#define LLVMDisassembler_VariantKind_ARM_LO16 2 /* :lower16: */
|
||||
|
||||
/**
|
||||
* The ARM64 target VariantKinds.
|
||||
*/
|
||||
#define LLVMDisassembler_VariantKind_ARM64_PAGE 1 /* @page */
|
||||
#define LLVMDisassembler_VariantKind_ARM64_PAGEOFF 2 /* @pageoff */
|
||||
#define LLVMDisassembler_VariantKind_ARM64_GOTPAGE 3 /* @gotpage */
|
||||
#define LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF 4 /* @gotpageoff */
|
||||
#define LLVMDisassembler_VariantKind_ARM64_TLVP 5 /* @tvlppage */
|
||||
#define LLVMDisassembler_VariantKind_ARM64_TLVOFF 6 /* @tvlppageoff */
|
||||
|
||||
/**
|
||||
* The type for the symbol lookup function. This may be called by the
|
||||
* disassembler for things like adding a comment for a PC plus a constant
|
||||
@ -123,6 +133,17 @@ typedef const char *(*LLVMSymbolLookupCallback)(void *DisInfo,
|
||||
/* The input reference is from a PC relative load instruction. */
|
||||
#define LLVMDisassembler_ReferenceType_In_PCrel_Load 2
|
||||
|
||||
/* The input reference is from an ARM64::ADRP instruction. */
|
||||
#define LLVMDisassembler_ReferenceType_In_ARM64_ADRP 0x100000001
|
||||
/* The input reference is from an ARM64::ADDXri instruction. */
|
||||
#define LLVMDisassembler_ReferenceType_In_ARM64_ADDXri 0x100000002
|
||||
/* The input reference is from an ARM64::LDRXui instruction. */
|
||||
#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXui 0x100000003
|
||||
/* The input reference is from an ARM64::LDRXl instruction. */
|
||||
#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXl 0x100000004
|
||||
/* The input reference is from an ARM64::ADR instruction. */
|
||||
#define LLVMDisassembler_ReferenceType_In_ARM64_ADR 0x100000005
|
||||
|
||||
/* The output reference is to as symbol stub. */
|
||||
#define LLVMDisassembler_ReferenceType_Out_SymbolStub 1
|
||||
/* The output reference is to a symbol address in a literal pool. */
|
||||
@ -141,6 +162,9 @@ typedef const char *(*LLVMSymbolLookupCallback)(void *DisInfo,
|
||||
/* The output reference is to a Objective-C class ref. */
|
||||
#define LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref 8
|
||||
|
||||
/* The output reference is to a C++ symbol name. */
|
||||
#define LLVMDisassembler_ReferenceType_DeMangled_Name 9
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* !defined(__cplusplus) */
|
||||
|
@ -163,6 +163,8 @@ void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE,
|
||||
LLVMValueRef Fn);
|
||||
|
||||
LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE);
|
||||
LLVMTargetMachineRef
|
||||
LLVMGetExecutionEngineTargetMachine(LLVMExecutionEngineRef EE);
|
||||
|
||||
void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
|
||||
void* Addr);
|
||||
|
@ -24,7 +24,7 @@ extern "C" {
|
||||
* Read LLVM IR from a memory buffer and convert it into an in-memory Module
|
||||
* object. Returns 0 on success.
|
||||
* Optionally returns a human-readable description of any errors that
|
||||
* occured during parsing IR. OutMessage must be disposed with
|
||||
* occurred during parsing IR. OutMessage must be disposed with
|
||||
* LLVMDisposeMessage.
|
||||
*
|
||||
* @see llvm::ParseIR()
|
||||
|
@ -78,7 +78,6 @@ void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef RI);
|
||||
// SymbolRef accessors
|
||||
const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI);
|
||||
uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI);
|
||||
uint64_t LLVMGetSymbolFileOffset(LLVMSymbolIteratorRef SI);
|
||||
uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI);
|
||||
|
||||
// RelocationRef accessors
|
||||
|
@ -14,12 +14,31 @@
|
||||
#ifndef LLVM_C_SUPPORT_H
|
||||
#define LLVM_C_SUPPORT_H
|
||||
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCSupportTypes Types and Enumerations
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef int LLVMBool;
|
||||
|
||||
/**
|
||||
* Used to pass regions of memory through LLVM interfaces.
|
||||
*
|
||||
* @see llvm::MemoryBuffer
|
||||
*/
|
||||
typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function permanently loads the dynamic library at the given path.
|
||||
* It is safe to call this function multiple times for the same library.
|
||||
|
@ -62,7 +62,7 @@ LLVMTargetRef LLVMGetFirstTarget(void);
|
||||
LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T);
|
||||
|
||||
/*===-- Target ------------------------------------------------------------===*/
|
||||
/** Finds the target corresponding to the given name and stores it in \p T.
|
||||
/** Finds the target corresponding to the given name and stores it in \p T.
|
||||
Returns 0 on success. */
|
||||
LLVMTargetRef LLVMGetTargetFromName(const char *Name);
|
||||
|
||||
@ -137,6 +137,9 @@ LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T, LLVMModuleR
|
||||
disposed with LLVMDisposeMessage. */
|
||||
char* LLVMGetDefaultTargetTriple(void);
|
||||
|
||||
/** Adds the target-specific analysis passes to the pass manager. */
|
||||
void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -19,7 +19,6 @@
|
||||
typedef struct LLVMOpaquePassManagerBuilder *LLVMPassManagerBuilderRef;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -41,6 +41,12 @@ void LLVMAddCFGSimplificationPass(LLVMPassManagerRef PM);
|
||||
/** See llvm::createDeadStoreEliminationPass function. */
|
||||
void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createScalarizerPass function. */
|
||||
void LLVMAddScalarizerPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createMergedLoadStoreMotionPass function. */
|
||||
void LLVMAddMergedLoadStoreMotionPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createGVNPass function. */
|
||||
void LLVMAddGVNPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
@ -40,8 +40,11 @@ typedef bool lto_bool_t;
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define LTO_API_VERSION 5
|
||||
#define LTO_API_VERSION 10
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
typedef enum {
|
||||
LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */
|
||||
LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0,
|
||||
@ -62,23 +65,29 @@ typedef enum {
|
||||
LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN = 0x00002800
|
||||
} lto_symbol_attributes;
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
typedef enum {
|
||||
LTO_DEBUG_MODEL_NONE = 0,
|
||||
LTO_DEBUG_MODEL_DWARF = 1
|
||||
} lto_debug_model;
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
typedef enum {
|
||||
LTO_CODEGEN_PIC_MODEL_STATIC = 0,
|
||||
LTO_CODEGEN_PIC_MODEL_DYNAMIC = 1,
|
||||
LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC = 2
|
||||
LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC = 2,
|
||||
LTO_CODEGEN_PIC_MODEL_DEFAULT = 3
|
||||
} lto_codegen_model;
|
||||
|
||||
|
||||
/** opaque reference to a loaded object module */
|
||||
typedef struct LTOModule* lto_module_t;
|
||||
typedef struct LLVMOpaqueLTOModule *lto_module_t;
|
||||
|
||||
/** opaque reference to a code generator */
|
||||
typedef struct LTOCodeGenerator* lto_code_gen_t;
|
||||
typedef struct LLVMOpaqueLTOCodeGenerator *lto_code_gen_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -86,6 +95,8 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* Returns a printable string.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern const char*
|
||||
lto_get_version(void);
|
||||
@ -93,12 +104,16 @@ lto_get_version(void);
|
||||
|
||||
/**
|
||||
* Returns the last error string or NULL if last operation was successful.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern const char*
|
||||
lto_get_error_message(void);
|
||||
|
||||
/**
|
||||
* Checks if a file is a loadable object file.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_module_is_object_file(const char* path);
|
||||
@ -106,6 +121,8 @@ lto_module_is_object_file(const char* path);
|
||||
|
||||
/**
|
||||
* Checks if a file is a loadable object compiled for requested target.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_module_is_object_file_for_target(const char* path,
|
||||
@ -114,6 +131,8 @@ lto_module_is_object_file_for_target(const char* path,
|
||||
|
||||
/**
|
||||
* Checks if a buffer is a loadable object file.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_module_is_object_file_in_memory(const void* mem, size_t length);
|
||||
@ -121,6 +140,8 @@ lto_module_is_object_file_in_memory(const void* mem, size_t length);
|
||||
|
||||
/**
|
||||
* Checks if a buffer is a loadable object compiled for requested target.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length,
|
||||
@ -130,6 +151,8 @@ lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length,
|
||||
/**
|
||||
* Loads an object file from disk.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_module_t
|
||||
lto_module_create(const char* path);
|
||||
@ -138,13 +161,27 @@ lto_module_create(const char* path);
|
||||
/**
|
||||
* Loads an object file from memory.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_module_t
|
||||
lto_module_create_from_memory(const void* mem, size_t length);
|
||||
|
||||
/**
|
||||
* Loads an object file from memory with an extra path argument.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=9
|
||||
*/
|
||||
extern lto_module_t
|
||||
lto_module_create_from_memory_with_path(const void* mem, size_t length,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* Loads an object file from disk. The seek point of fd is not preserved.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since LTO_API_VERSION=5
|
||||
*/
|
||||
extern lto_module_t
|
||||
lto_module_create_from_fd(int fd, const char *path, size_t file_size);
|
||||
@ -152,28 +189,34 @@ lto_module_create_from_fd(int fd, const char *path, size_t file_size);
|
||||
/**
|
||||
* Loads an object file from disk. The seek point of fd is not preserved.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since LTO_API_VERSION=5
|
||||
*/
|
||||
extern lto_module_t
|
||||
lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size,
|
||||
size_t map_size, off_t offset);
|
||||
|
||||
|
||||
/**
|
||||
* Frees all memory internally allocated by the module.
|
||||
* Upon return the lto_module_t is no longer valid.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern void
|
||||
lto_module_dispose(lto_module_t mod);
|
||||
|
||||
|
||||
/**
|
||||
* Returns triple string which the object module was compiled under.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern const char*
|
||||
lto_module_get_target_triple(lto_module_t mod);
|
||||
|
||||
/**
|
||||
* Sets triple string with which the object will be codegened.
|
||||
*
|
||||
* \since LTO_API_VERSION=4
|
||||
*/
|
||||
extern void
|
||||
lto_module_set_target_triple(lto_module_t mod, const char *triple);
|
||||
@ -181,6 +224,8 @@ lto_module_set_target_triple(lto_module_t mod, const char *triple);
|
||||
|
||||
/**
|
||||
* Returns the number of symbols in the object module.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern unsigned int
|
||||
lto_module_get_num_symbols(lto_module_t mod);
|
||||
@ -188,6 +233,8 @@ lto_module_get_num_symbols(lto_module_t mod);
|
||||
|
||||
/**
|
||||
* Returns the name of the ith symbol in the object module.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern const char*
|
||||
lto_module_get_symbol_name(lto_module_t mod, unsigned int index);
|
||||
@ -195,40 +242,116 @@ lto_module_get_symbol_name(lto_module_t mod, unsigned int index);
|
||||
|
||||
/**
|
||||
* Returns the attributes of the ith symbol in the object module.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_symbol_attributes
|
||||
lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of dependent libraries in the object module.
|
||||
*
|
||||
* \since LTO_API_VERSION=8
|
||||
*/
|
||||
extern unsigned int
|
||||
lto_module_get_num_deplibs(lto_module_t mod);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ith dependent library in the module.
|
||||
*
|
||||
* \since LTO_API_VERSION=8
|
||||
*/
|
||||
extern const char*
|
||||
lto_module_get_deplib(lto_module_t mod, unsigned int index);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of linker options in the object module.
|
||||
*
|
||||
* \since LTO_API_VERSION=8
|
||||
*/
|
||||
extern unsigned int
|
||||
lto_module_get_num_linkeropts(lto_module_t mod);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ith linker option in the module.
|
||||
*
|
||||
* \since LTO_API_VERSION=8
|
||||
*/
|
||||
extern const char*
|
||||
lto_module_get_linkeropt(lto_module_t mod, unsigned int index);
|
||||
|
||||
|
||||
/**
|
||||
* Diagnostic severity.
|
||||
*
|
||||
* \since LTO_API_VERSION=7
|
||||
*/
|
||||
typedef enum {
|
||||
LTO_DS_ERROR = 0,
|
||||
LTO_DS_WARNING = 1,
|
||||
LTO_DS_REMARK = 3, // Added in LTO_API_VERSION=10.
|
||||
LTO_DS_NOTE = 2
|
||||
} lto_codegen_diagnostic_severity_t;
|
||||
|
||||
/**
|
||||
* Diagnostic handler type.
|
||||
* \p severity defines the severity.
|
||||
* \p diag is the actual diagnostic.
|
||||
* The diagnostic is not prefixed by any of severity keyword, e.g., 'error: '.
|
||||
* \p ctxt is used to pass the context set with the diagnostic handler.
|
||||
*
|
||||
* \since LTO_API_VERSION=7
|
||||
*/
|
||||
typedef void (*lto_diagnostic_handler_t)(
|
||||
lto_codegen_diagnostic_severity_t severity, const char *diag, void *ctxt);
|
||||
|
||||
/**
|
||||
* Set a diagnostic handler and the related context (void *).
|
||||
* This is more general than lto_get_error_message, as the diagnostic handler
|
||||
* can be called at anytime within lto.
|
||||
*
|
||||
* \since LTO_API_VERSION=7
|
||||
*/
|
||||
extern void lto_codegen_set_diagnostic_handler(lto_code_gen_t,
|
||||
lto_diagnostic_handler_t,
|
||||
void *);
|
||||
|
||||
/**
|
||||
* Instantiates a code generator.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_code_gen_t
|
||||
lto_codegen_create(void);
|
||||
|
||||
|
||||
/**
|
||||
* Frees all code generator and all memory it internally allocated.
|
||||
* Upon return the lto_code_gen_t is no longer valid.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_dispose(lto_code_gen_t);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add an object module to the set of modules for which code will be generated.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets if debug info should be generated.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model);
|
||||
@ -237,6 +360,8 @@ lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model);
|
||||
/**
|
||||
* Sets which PIC code model to generated.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model);
|
||||
@ -244,6 +369,8 @@ lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model);
|
||||
|
||||
/**
|
||||
* Sets the cpu to generate code for.
|
||||
*
|
||||
* \since LTO_API_VERSION=4
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu);
|
||||
@ -252,20 +379,27 @@ lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu);
|
||||
/**
|
||||
* Sets the location of the assembler tool to run. If not set, libLTO
|
||||
* will use gcc to invoke the assembler.
|
||||
*
|
||||
* \since LTO_API_VERSION=3
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path);
|
||||
|
||||
/**
|
||||
* Sets extra arguments that libLTO should pass to the assembler.
|
||||
*
|
||||
* \since LTO_API_VERSION=4
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args,
|
||||
int nargs);
|
||||
|
||||
/**
|
||||
* Tells LTO optimization passes that this symbol must be preserved
|
||||
* because it is referenced by native code or a command line option.
|
||||
* Adds to a list of all global symbols that must exist in the final generated
|
||||
* code. If a function is not listed there, it might be inlined into every usage
|
||||
* and optimized away.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol);
|
||||
@ -274,6 +408,8 @@ lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol);
|
||||
* Writes a new object file at the specified path that contains the
|
||||
* merged contents of all modules added so far.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since LTO_API_VERSION=5
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path);
|
||||
@ -285,6 +421,8 @@ lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path);
|
||||
* lto_code_gen_t and will be freed when lto_codegen_dispose()
|
||||
* is called, or lto_codegen_compile() is called again.
|
||||
* On failure, returns NULL (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern const void*
|
||||
lto_codegen_compile(lto_code_gen_t cg, size_t* length);
|
||||
@ -292,6 +430,8 @@ lto_codegen_compile(lto_code_gen_t cg, size_t* length);
|
||||
/**
|
||||
* Generates code for all added modules into one native object file.
|
||||
* The name of the file is written to name. Returns true on error.
|
||||
*
|
||||
* \since LTO_API_VERSION=5
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_codegen_compile_to_file(lto_code_gen_t cg, const char** name);
|
||||
@ -299,6 +439,8 @@ lto_codegen_compile_to_file(lto_code_gen_t cg, const char** name);
|
||||
|
||||
/**
|
||||
* Sets options to help debug codegen bugs.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_debug_options(lto_code_gen_t cg, const char *);
|
||||
@ -306,6 +448,8 @@ lto_codegen_debug_options(lto_code_gen_t cg, const char *);
|
||||
/**
|
||||
* Initializes LLVM disassemblers.
|
||||
* FIXME: This doesn't really belong here.
|
||||
*
|
||||
* \since LTO_API_VERSION=5
|
||||
*/
|
||||
extern void
|
||||
lto_initialize_disassembler(void);
|
||||
|
4
contrib/llvm/include/llvm-c/module.modulemap
Normal file
4
contrib/llvm/include/llvm-c/module.modulemap
Normal file
@ -0,0 +1,4 @@
|
||||
module LLVM_C {
|
||||
umbrella "."
|
||||
module * { export * }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//== llvm/Support/APFloat.h - Arbitrary Precision Floating Point -*- C++ -*-==//
|
||||
//===- llvm/ADT/APFloat.h - Arbitrary Precision Floating Point ---*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -196,6 +196,7 @@ public:
|
||||
explicit APFloat(double d);
|
||||
explicit APFloat(float f);
|
||||
APFloat(const APFloat &);
|
||||
APFloat(APFloat &&);
|
||||
~APFloat();
|
||||
|
||||
/// @}
|
||||
@ -235,19 +236,19 @@ public:
|
||||
APInt fill(64, type);
|
||||
return getQNaN(Sem, Negative, &fill);
|
||||
} else {
|
||||
return getQNaN(Sem, Negative, 0);
|
||||
return getQNaN(Sem, Negative, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Factory for QNaN values.
|
||||
static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
|
||||
const APInt *payload = 0) {
|
||||
const APInt *payload = nullptr) {
|
||||
return makeNaN(Sem, false, Negative, payload);
|
||||
}
|
||||
|
||||
/// Factory for SNaN values.
|
||||
static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
|
||||
const APInt *payload = 0) {
|
||||
const APInt *payload = nullptr) {
|
||||
return makeNaN(Sem, true, Negative, payload);
|
||||
}
|
||||
|
||||
@ -411,6 +412,7 @@ public:
|
||||
/// @}
|
||||
|
||||
APFloat &operator=(const APFloat &);
|
||||
APFloat &operator=(APFloat &&);
|
||||
|
||||
/// \brief Overload to compute a hash code for an APFloat value.
|
||||
///
|
||||
@ -498,7 +500,8 @@ private:
|
||||
|
||||
void makeLargest(bool Neg = false);
|
||||
void makeSmallest(bool Neg = false);
|
||||
void makeNaN(bool SNaN = false, bool Neg = false, const APInt *fill = 0);
|
||||
void makeNaN(bool SNaN = false, bool Neg = false,
|
||||
const APInt *fill = nullptr);
|
||||
static APFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
|
||||
const APInt *fill);
|
||||
void makeInf(bool Neg = false);
|
||||
|
@ -284,12 +284,10 @@ public:
|
||||
initSlowCase(that);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
/// \brief Move Constructor.
|
||||
APInt(APInt &&that) : BitWidth(that.BitWidth), VAL(that.VAL) {
|
||||
that.BitWidth = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Destructor.
|
||||
~APInt() {
|
||||
@ -656,7 +654,6 @@ public:
|
||||
return AssignSlowCase(RHS);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
/// @brief Move assignment operator.
|
||||
APInt &operator=(APInt &&that) {
|
||||
if (!isSingleWord())
|
||||
@ -669,7 +666,6 @@ public:
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Assignment operator.
|
||||
///
|
||||
@ -1265,7 +1261,7 @@ public:
|
||||
/// \returns the number of words to hold the integer value with a given bit
|
||||
/// width.
|
||||
static unsigned getNumWords(unsigned BitWidth) {
|
||||
return (BitWidth + APINT_BITS_PER_WORD - 1) / APINT_BITS_PER_WORD;
|
||||
return ((uint64_t)BitWidth + APINT_BITS_PER_WORD - 1) / APINT_BITS_PER_WORD;
|
||||
}
|
||||
|
||||
/// \brief Compute the number of active bits in the value
|
||||
@ -1504,6 +1500,35 @@ public:
|
||||
return BitWidth - (*this - 1).countLeadingZeros();
|
||||
}
|
||||
|
||||
/// \returns the nearest log base 2 of this APInt. Ties round up.
|
||||
///
|
||||
/// NOTE: When we have a BitWidth of 1, we define:
|
||||
///
|
||||
/// log2(0) = UINT32_MAX
|
||||
/// log2(1) = 0
|
||||
///
|
||||
/// to get around any mathematical concerns resulting from
|
||||
/// referencing 2 in a space where 2 does no exist.
|
||||
unsigned nearestLogBase2() const {
|
||||
// Special case when we have a bitwidth of 1. If VAL is 1, then we
|
||||
// get 0. If VAL is 0, we get UINT64_MAX which gets truncated to
|
||||
// UINT32_MAX.
|
||||
if (BitWidth == 1)
|
||||
return VAL - 1;
|
||||
|
||||
// Handle the zero case.
|
||||
if (!getBoolValue())
|
||||
return UINT32_MAX;
|
||||
|
||||
// The non-zero case is handled by computing:
|
||||
//
|
||||
// nearestLogBase2(x) = logBase2(x) + x[logBase2(x)-1].
|
||||
//
|
||||
// where x[i] is referring to the value of the ith bit of x.
|
||||
unsigned lg = logBase2();
|
||||
return lg + unsigned((*this)[lg - 1]);
|
||||
}
|
||||
|
||||
/// \returns the log base 2 of this APInt if its an exact power of two, -1
|
||||
/// otherwise
|
||||
int32_t exactLogBase2() const {
|
||||
|
@ -30,18 +30,12 @@ public:
|
||||
explicit APSInt(uint32_t BitWidth, bool isUnsigned = true)
|
||||
: APInt(BitWidth, 0), IsUnsigned(isUnsigned) {}
|
||||
|
||||
explicit APSInt(const APInt &I, bool isUnsigned = true)
|
||||
: APInt(I), IsUnsigned(isUnsigned) {}
|
||||
explicit APSInt(APInt I, bool isUnsigned = true)
|
||||
: APInt(std::move(I)), IsUnsigned(isUnsigned) {}
|
||||
|
||||
APSInt &operator=(const APSInt &RHS) {
|
||||
APInt::operator=(RHS);
|
||||
IsUnsigned = RHS.IsUnsigned;
|
||||
return *this;
|
||||
}
|
||||
|
||||
APSInt &operator=(const APInt &RHS) {
|
||||
APSInt &operator=(APInt RHS) {
|
||||
// Retain our current sign.
|
||||
APInt::operator=(RHS);
|
||||
APInt::operator=(std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -62,7 +56,7 @@ public:
|
||||
APInt::toString(Str, Radix, isSigned());
|
||||
}
|
||||
/// toString - Converts an APInt to a std::string. This is an inefficient
|
||||
/// method, your should prefer passing in a SmallString instead.
|
||||
/// method; you should prefer passing in a SmallString instead.
|
||||
std::string toString(unsigned Radix) const {
|
||||
return APInt::toString(Radix, isSigned());
|
||||
}
|
||||
|
@ -48,10 +48,10 @@ namespace llvm {
|
||||
/// @{
|
||||
|
||||
/// Construct an empty ArrayRef.
|
||||
/*implicit*/ ArrayRef() : Data(0), Length(0) {}
|
||||
/*implicit*/ ArrayRef() : Data(nullptr), Length(0) {}
|
||||
|
||||
/// Construct an empty ArrayRef from None.
|
||||
/*implicit*/ ArrayRef(NoneType) : Data(0), Length(0) {}
|
||||
/*implicit*/ ArrayRef(NoneType) : Data(nullptr), Length(0) {}
|
||||
|
||||
/// Construct an ArrayRef from a single element.
|
||||
/*implicit*/ ArrayRef(const T &OneElt)
|
||||
@ -76,7 +76,7 @@ namespace llvm {
|
||||
/// Construct an ArrayRef from a std::vector.
|
||||
template<typename A>
|
||||
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
|
||||
: Data(Vec.empty() ? (T*)0 : &Vec[0]), Length(Vec.size()) {}
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// Construct an ArrayRef from a C array.
|
||||
template <size_t N>
|
||||
@ -120,14 +120,18 @@ namespace llvm {
|
||||
return Data[Length-1];
|
||||
}
|
||||
|
||||
// copy - Allocate copy in Allocator and return ArrayRef<T> to it.
|
||||
template <typename Allocator> ArrayRef<T> copy(Allocator &A) {
|
||||
T *Buff = A.template Allocate<T>(Length);
|
||||
std::copy(begin(), end(), Buff);
|
||||
return ArrayRef<T>(Buff, Length);
|
||||
}
|
||||
|
||||
/// equals - Check for element-wise equality.
|
||||
bool equals(ArrayRef RHS) const {
|
||||
if (Length != RHS.Length)
|
||||
return false;
|
||||
for (size_type i = 0; i != Length; i++)
|
||||
if (Data[i] != RHS.Data[i])
|
||||
return false;
|
||||
return true;
|
||||
return std::equal(begin(), end(), RHS.begin());
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
@ -143,6 +147,12 @@ namespace llvm {
|
||||
return ArrayRef<T>(data()+N, M);
|
||||
}
|
||||
|
||||
// \brief Drop the last \p N elements of the array.
|
||||
ArrayRef<T> drop_back(unsigned N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return slice(0, size() - N);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
@ -213,7 +223,7 @@ namespace llvm {
|
||||
|
||||
/// Construct an MutableArrayRef from a C array.
|
||||
template <size_t N>
|
||||
/*implicit*/ MutableArrayRef(T (&Arr)[N])
|
||||
/*implicit*/ LLVM_CONSTEXPR MutableArrayRef(T (&Arr)[N])
|
||||
: ArrayRef<T>(Arr) {}
|
||||
|
||||
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
|
||||
|
@ -34,6 +34,7 @@ class BitVector {
|
||||
unsigned Capacity; // Size of allocated memory in BitWord.
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
// Encapsulation of a single bit.
|
||||
class reference {
|
||||
friend class BitVector;
|
||||
@ -58,21 +59,21 @@ public:
|
||||
|
||||
reference& operator=(bool t) {
|
||||
if (t)
|
||||
*WordRef |= 1L << BitPos;
|
||||
*WordRef |= BitWord(1) << BitPos;
|
||||
else
|
||||
*WordRef &= ~(1L << BitPos);
|
||||
*WordRef &= ~(BitWord(1) << BitPos);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return ((*WordRef) & (1L << BitPos)) ? true : false;
|
||||
return ((*WordRef) & (BitWord(1) << BitPos)) ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// BitVector default ctor - Creates an empty bitvector.
|
||||
BitVector() : Size(0), Capacity(0) {
|
||||
Bits = 0;
|
||||
Bits = nullptr;
|
||||
}
|
||||
|
||||
/// BitVector ctor - Creates a bitvector of specified number of bits. All
|
||||
@ -88,7 +89,7 @@ public:
|
||||
/// BitVector copy ctor.
|
||||
BitVector(const BitVector &RHS) : Size(RHS.size()) {
|
||||
if (Size == 0) {
|
||||
Bits = 0;
|
||||
Bits = nullptr;
|
||||
Capacity = 0;
|
||||
return;
|
||||
}
|
||||
@ -98,12 +99,10 @@ public:
|
||||
std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord));
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
BitVector(BitVector &&RHS)
|
||||
: Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
|
||||
RHS.Bits = 0;
|
||||
RHS.Bits = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
~BitVector() {
|
||||
std::free(Bits);
|
||||
@ -113,10 +112,10 @@ public:
|
||||
bool empty() const { return Size == 0; }
|
||||
|
||||
/// size - Returns the number of bits in this bitvector.
|
||||
unsigned size() const { return Size; }
|
||||
size_type size() const { return Size; }
|
||||
|
||||
/// count - Returns the number of bits which are set.
|
||||
unsigned count() const {
|
||||
size_type count() const {
|
||||
unsigned NumBits = 0;
|
||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
||||
if (sizeof(BitWord) == 4)
|
||||
@ -240,7 +239,7 @@ public:
|
||||
}
|
||||
|
||||
BitVector &set(unsigned Idx) {
|
||||
Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE);
|
||||
Bits[Idx / BITWORD_SIZE] |= BitWord(1) << (Idx % BITWORD_SIZE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -267,7 +266,8 @@ public:
|
||||
Bits[I / BITWORD_SIZE] = ~0UL;
|
||||
|
||||
BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1;
|
||||
Bits[I / BITWORD_SIZE] |= PostfixMask;
|
||||
if (I < E)
|
||||
Bits[I / BITWORD_SIZE] |= PostfixMask;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -278,7 +278,7 @@ public:
|
||||
}
|
||||
|
||||
BitVector &reset(unsigned Idx) {
|
||||
Bits[Idx / BITWORD_SIZE] &= ~(1L << (Idx % BITWORD_SIZE));
|
||||
Bits[Idx / BITWORD_SIZE] &= ~(BitWord(1) << (Idx % BITWORD_SIZE));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -305,7 +305,8 @@ public:
|
||||
Bits[I / BITWORD_SIZE] = 0UL;
|
||||
|
||||
BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1;
|
||||
Bits[I / BITWORD_SIZE] &= ~PostfixMask;
|
||||
if (I < E)
|
||||
Bits[I / BITWORD_SIZE] &= ~PostfixMask;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -318,7 +319,7 @@ public:
|
||||
}
|
||||
|
||||
BitVector &flip(unsigned Idx) {
|
||||
Bits[Idx / BITWORD_SIZE] ^= 1L << (Idx % BITWORD_SIZE);
|
||||
Bits[Idx / BITWORD_SIZE] ^= BitWord(1) << (Idx % BITWORD_SIZE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -330,7 +331,7 @@ public:
|
||||
|
||||
bool operator[](unsigned Idx) const {
|
||||
assert (Idx < Size && "Out-of-bounds Bit access.");
|
||||
BitWord Mask = 1L << (Idx % BITWORD_SIZE);
|
||||
BitWord Mask = BitWord(1) << (Idx % BITWORD_SIZE);
|
||||
return (Bits[Idx / BITWORD_SIZE] & Mask) != 0;
|
||||
}
|
||||
|
||||
@ -459,7 +460,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
const BitVector &operator=(BitVector &&RHS) {
|
||||
if (this == &RHS) return *this;
|
||||
|
||||
@ -468,11 +468,10 @@ public:
|
||||
Size = RHS.Size;
|
||||
Capacity = RHS.Capacity;
|
||||
|
||||
RHS.Bits = 0;
|
||||
RHS.Bits = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(BitVector &RHS) {
|
||||
std::swap(Bits, RHS.Bits);
|
||||
|
@ -43,6 +43,7 @@ protected:
|
||||
typedef std::pair<KeyT, ValueT> BucketT;
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
typedef KeyT key_type;
|
||||
typedef ValueT mapped_type;
|
||||
typedef BucketT value_type;
|
||||
@ -70,7 +71,7 @@ public:
|
||||
unsigned size() const { return getNumEntries(); }
|
||||
|
||||
/// Grow the densemap so that it has at least Size buckets. Does not shrink
|
||||
void resize(size_t Size) {
|
||||
void resize(size_type Size) {
|
||||
if (Size > getNumBuckets())
|
||||
grow(Size);
|
||||
}
|
||||
@ -99,10 +100,10 @@ public:
|
||||
setNumTombstones(0);
|
||||
}
|
||||
|
||||
/// count - Return true if the specified key is in the map.
|
||||
bool count(const KeyT &Val) const {
|
||||
/// Return 1 if the specified key is in the map, 0 otherwise.
|
||||
size_type count(const KeyT &Val) const {
|
||||
const BucketT *TheBucket;
|
||||
return LookupBucketFor(Val, TheBucket);
|
||||
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
|
||||
}
|
||||
|
||||
iterator find(const KeyT &Val) {
|
||||
@ -161,7 +162,6 @@ public:
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||
// If the key is already in the map, it returns false and doesn't update the
|
||||
// value.
|
||||
@ -177,8 +177,7 @@ public:
|
||||
TheBucket);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// insert - Range insertion of pairs.
|
||||
template<typename InputIt>
|
||||
void insert(InputIt I, InputIt E) {
|
||||
@ -218,7 +217,6 @@ public:
|
||||
return FindAndConstruct(Key).second;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
value_type& FindAndConstruct(KeyT &&Key) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Key, TheBucket))
|
||||
@ -230,7 +228,6 @@ public:
|
||||
ValueT &operator[](KeyT &&Key) {
|
||||
return FindAndConstruct(std::move(Key)).second;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// isPointerIntoBucketsArray - Return true if the specified pointer points
|
||||
/// somewhere into the DenseMap's array of buckets (i.e. either to a key or
|
||||
@ -289,8 +286,8 @@ protected:
|
||||
bool FoundVal = LookupBucketFor(B->first, DestBucket);
|
||||
(void)FoundVal; // silence warning.
|
||||
assert(!FoundVal && "Key already in new map?");
|
||||
DestBucket->first = llvm_move(B->first);
|
||||
new (&DestBucket->second) ValueT(llvm_move(B->second));
|
||||
DestBucket->first = std::move(B->first);
|
||||
new (&DestBucket->second) ValueT(std::move(B->second));
|
||||
incrementNumEntries();
|
||||
|
||||
// Free the value.
|
||||
@ -403,7 +400,6 @@ private:
|
||||
return TheBucket;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
|
||||
BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
|
||||
@ -420,7 +416,6 @@ private:
|
||||
new (&TheBucket->second) ValueT(std::move(Value));
|
||||
return TheBucket;
|
||||
}
|
||||
#endif
|
||||
|
||||
BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
|
||||
// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
|
||||
@ -467,12 +462,12 @@ private:
|
||||
const unsigned NumBuckets = getNumBuckets();
|
||||
|
||||
if (NumBuckets == 0) {
|
||||
FoundBucket = 0;
|
||||
FoundBucket = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// FoundTombstone - Keep track of whether we find a tombstone while probing.
|
||||
const BucketT *FoundTombstone = 0;
|
||||
const BucketT *FoundTombstone = nullptr;
|
||||
const KeyT EmptyKey = getEmptyKey();
|
||||
const KeyT TombstoneKey = getTombstoneKey();
|
||||
assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
|
||||
@ -555,12 +550,10 @@ public:
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
DenseMap(DenseMap &&other) : BaseT() {
|
||||
init(0);
|
||||
swap(other);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename InputIt>
|
||||
DenseMap(const InputIt &I, const InputIt &E) {
|
||||
@ -585,7 +578,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
DenseMap& operator=(DenseMap &&other) {
|
||||
this->destroyAll();
|
||||
operator delete(Buckets);
|
||||
@ -593,7 +585,6 @@ public:
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void copyFrom(const DenseMap& other) {
|
||||
this->destroyAll();
|
||||
@ -675,7 +666,7 @@ private:
|
||||
bool allocateBuckets(unsigned Num) {
|
||||
NumBuckets = Num;
|
||||
if (NumBuckets == 0) {
|
||||
Buckets = 0;
|
||||
Buckets = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -719,12 +710,10 @@ public:
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
SmallDenseMap(SmallDenseMap &&other) : BaseT() {
|
||||
init(0);
|
||||
swap(other);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename InputIt>
|
||||
SmallDenseMap(const InputIt &I, const InputIt &E) {
|
||||
@ -765,10 +754,10 @@ public:
|
||||
// Swap separately and handle any assymetry.
|
||||
std::swap(LHSB->first, RHSB->first);
|
||||
if (hasLHSValue) {
|
||||
new (&RHSB->second) ValueT(llvm_move(LHSB->second));
|
||||
new (&RHSB->second) ValueT(std::move(LHSB->second));
|
||||
LHSB->second.~ValueT();
|
||||
} else if (hasRHSValue) {
|
||||
new (&LHSB->second) ValueT(llvm_move(RHSB->second));
|
||||
new (&LHSB->second) ValueT(std::move(RHSB->second));
|
||||
RHSB->second.~ValueT();
|
||||
}
|
||||
}
|
||||
@ -784,7 +773,7 @@ public:
|
||||
SmallDenseMap &LargeSide = Small ? RHS : *this;
|
||||
|
||||
// First stash the large side's rep and move the small side across.
|
||||
LargeRep TmpRep = llvm_move(*LargeSide.getLargeRep());
|
||||
LargeRep TmpRep = std::move(*LargeSide.getLargeRep());
|
||||
LargeSide.getLargeRep()->~LargeRep();
|
||||
LargeSide.Small = true;
|
||||
// This is similar to the standard move-from-old-buckets, but the bucket
|
||||
@ -794,11 +783,11 @@ public:
|
||||
for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
|
||||
BucketT *NewB = &LargeSide.getInlineBuckets()[i],
|
||||
*OldB = &SmallSide.getInlineBuckets()[i];
|
||||
new (&NewB->first) KeyT(llvm_move(OldB->first));
|
||||
new (&NewB->first) KeyT(std::move(OldB->first));
|
||||
OldB->first.~KeyT();
|
||||
if (!KeyInfoT::isEqual(NewB->first, EmptyKey) &&
|
||||
!KeyInfoT::isEqual(NewB->first, TombstoneKey)) {
|
||||
new (&NewB->second) ValueT(llvm_move(OldB->second));
|
||||
new (&NewB->second) ValueT(std::move(OldB->second));
|
||||
OldB->second.~ValueT();
|
||||
}
|
||||
}
|
||||
@ -806,7 +795,7 @@ public:
|
||||
// The hard part of moving the small buckets across is done, just move
|
||||
// the TmpRep into its new home.
|
||||
SmallSide.Small = false;
|
||||
new (SmallSide.getLargeRep()) LargeRep(llvm_move(TmpRep));
|
||||
new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep));
|
||||
}
|
||||
|
||||
SmallDenseMap& operator=(const SmallDenseMap& other) {
|
||||
@ -814,7 +803,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
SmallDenseMap& operator=(SmallDenseMap &&other) {
|
||||
this->destroyAll();
|
||||
deallocateBuckets();
|
||||
@ -822,7 +810,6 @@ public:
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void copyFrom(const SmallDenseMap& other) {
|
||||
this->destroyAll();
|
||||
@ -830,7 +817,7 @@ public:
|
||||
Small = true;
|
||||
if (other.getNumBuckets() > InlineBuckets) {
|
||||
Small = false;
|
||||
allocateBuckets(other.getNumBuckets());
|
||||
new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets()));
|
||||
}
|
||||
this->BaseT::copyFrom(other);
|
||||
}
|
||||
@ -866,8 +853,8 @@ public:
|
||||
!KeyInfoT::isEqual(P->first, TombstoneKey)) {
|
||||
assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&
|
||||
"Too many inline buckets!");
|
||||
new (&TmpEnd->first) KeyT(llvm_move(P->first));
|
||||
new (&TmpEnd->second) ValueT(llvm_move(P->second));
|
||||
new (&TmpEnd->first) KeyT(std::move(P->first));
|
||||
new (&TmpEnd->second) ValueT(std::move(P->second));
|
||||
++TmpEnd;
|
||||
P->second.~ValueT();
|
||||
}
|
||||
@ -882,7 +869,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
LargeRep OldRep = llvm_move(*getLargeRep());
|
||||
LargeRep OldRep = std::move(*getLargeRep());
|
||||
getLargeRep()->~LargeRep();
|
||||
if (AtLeast <= InlineBuckets) {
|
||||
Small = true;
|
||||
@ -991,14 +978,15 @@ class DenseMapIterator {
|
||||
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>;
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef typename conditional<IsConst, const Bucket, Bucket>::type value_type;
|
||||
typedef typename std::conditional<IsConst, const Bucket, Bucket>::type
|
||||
value_type;
|
||||
typedef value_type *pointer;
|
||||
typedef value_type &reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
private:
|
||||
pointer Ptr, End;
|
||||
public:
|
||||
DenseMapIterator() : Ptr(0), End(0) {}
|
||||
DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
|
||||
|
||||
DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
|
||||
: Ptr(Pos), End(E) {
|
||||
|
@ -27,11 +27,14 @@ class DenseSet {
|
||||
typedef DenseMap<ValueT, char, ValueInfoT> MapTy;
|
||||
MapTy TheMap;
|
||||
public:
|
||||
DenseSet(const DenseSet &Other) : TheMap(Other.TheMap) {}
|
||||
typedef ValueT key_type;
|
||||
typedef ValueT value_type;
|
||||
typedef unsigned size_type;
|
||||
|
||||
explicit DenseSet(unsigned NumInitBuckets = 0) : TheMap(NumInitBuckets) {}
|
||||
|
||||
bool empty() const { return TheMap.empty(); }
|
||||
unsigned size() const { return TheMap.size(); }
|
||||
size_type size() const { return TheMap.size(); }
|
||||
size_t getMemorySize() const { return TheMap.getMemorySize(); }
|
||||
|
||||
/// Grow the DenseSet so that it has at least Size buckets. Will not shrink
|
||||
@ -42,7 +45,8 @@ public:
|
||||
TheMap.clear();
|
||||
}
|
||||
|
||||
bool count(const ValueT &V) const {
|
||||
/// Return 1 if the specified key is in the set, 0 otherwise.
|
||||
size_type count(const ValueT &V) const {
|
||||
return TheMap.count(V);
|
||||
}
|
||||
|
||||
@ -54,11 +58,6 @@ public:
|
||||
TheMap.swap(RHS.TheMap);
|
||||
}
|
||||
|
||||
DenseSet &operator=(const DenseSet &RHS) {
|
||||
TheMap = RHS.TheMap;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
|
||||
class Iterator {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#ifndef LLVM_ADT_DEPTHFIRSTITERATOR_H
|
||||
#define LLVM_ADT_DEPTHFIRSTITERATOR_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
@ -207,6 +208,12 @@ df_iterator<T> df_end(const T& G) {
|
||||
return df_iterator<T>::end(G);
|
||||
}
|
||||
|
||||
// Provide an accessor method to use them in range-based patterns.
|
||||
template <class T>
|
||||
iterator_range<df_iterator<T>> depth_first(const T& G) {
|
||||
return iterator_range<df_iterator<T>>(df_begin(G), df_end(G));
|
||||
}
|
||||
|
||||
// Provide global definitions of external depth first iterators...
|
||||
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
|
||||
struct df_ext_iterator : public df_iterator<T, SetTy, true> {
|
||||
@ -244,6 +251,12 @@ idf_iterator<T> idf_end(const T& G){
|
||||
return idf_iterator<T>::end(Inverse<T>(G));
|
||||
}
|
||||
|
||||
// Provide an accessor method to use them in range-based patterns.
|
||||
template <class T>
|
||||
iterator_range<idf_iterator<T>> inverse_depth_first(const T& G) {
|
||||
return iterator_range<idf_iterator<T>>(idf_begin(G), idf_end(G));
|
||||
}
|
||||
|
||||
// Provide global definitions of external inverse depth first iterators...
|
||||
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
|
||||
struct idf_ext_iterator : public idf_iterator<T, SetTy, true> {
|
||||
|
@ -86,14 +86,14 @@ class EquivalenceClasses {
|
||||
}
|
||||
|
||||
void setNext(const ECValue *NewNext) const {
|
||||
assert(getNext() == 0 && "Already has a next pointer!");
|
||||
assert(getNext() == nullptr && "Already has a next pointer!");
|
||||
Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
|
||||
}
|
||||
public:
|
||||
ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
|
||||
Data(RHS.Data) {
|
||||
// Only support copying of singleton nodes.
|
||||
assert(RHS.isLeader() && RHS.getNext() == 0 && "Not a singleton!");
|
||||
assert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
|
||||
}
|
||||
|
||||
bool operator<(const ECValue &UFN) const { return Data < UFN.Data; }
|
||||
@ -147,10 +147,10 @@ public:
|
||||
class member_iterator;
|
||||
member_iterator member_begin(iterator I) const {
|
||||
// Only leaders provide anything to iterate over.
|
||||
return member_iterator(I->isLeader() ? &*I : 0);
|
||||
return member_iterator(I->isLeader() ? &*I : nullptr);
|
||||
}
|
||||
member_iterator member_end() const {
|
||||
return member_iterator(0);
|
||||
return member_iterator(nullptr);
|
||||
}
|
||||
|
||||
/// findValue - Return an iterator to the specified value. If it does not
|
||||
@ -249,16 +249,15 @@ public:
|
||||
|
||||
explicit member_iterator() {}
|
||||
explicit member_iterator(const ECValue *N) : Node(N) {}
|
||||
member_iterator(const member_iterator &I) : Node(I.Node) {}
|
||||
|
||||
reference operator*() const {
|
||||
assert(Node != 0 && "Dereferencing end()!");
|
||||
assert(Node != nullptr && "Dereferencing end()!");
|
||||
return Node->getData();
|
||||
}
|
||||
reference operator->() const { return operator*(); }
|
||||
|
||||
member_iterator &operator++() {
|
||||
assert(Node != 0 && "++'d off the end of the list!");
|
||||
assert(Node != nullptr && "++'d off the end of the list!");
|
||||
Node = Node->getNext();
|
||||
return *this;
|
||||
}
|
||||
|
@ -18,12 +18,12 @@
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
class APFloat;
|
||||
class APInt;
|
||||
class BumpPtrAllocator;
|
||||
|
||||
/// This folding set used for two purposes:
|
||||
/// 1. Given information about a node we want to create, look up the unique
|
||||
@ -137,7 +137,7 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
Node() : NextInFoldingSetBucket(0) {}
|
||||
Node() : NextInFoldingSetBucket(nullptr) {}
|
||||
|
||||
// Accessors
|
||||
void *getNextInBucket() const { return NextInFoldingSetBucket; }
|
||||
@ -269,7 +269,7 @@ class FoldingSetNodeIDRef {
|
||||
const unsigned *Data;
|
||||
size_t Size;
|
||||
public:
|
||||
FoldingSetNodeIDRef() : Data(0), Size(0) {}
|
||||
FoldingSetNodeIDRef() : Data(nullptr), Size(0) {}
|
||||
FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
|
||||
|
||||
/// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
|
||||
@ -278,6 +278,8 @@ public:
|
||||
|
||||
bool operator==(FoldingSetNodeIDRef) const;
|
||||
|
||||
bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
|
||||
|
||||
/// Used to compare the "ordering" of two nodes as defined by the
|
||||
/// profiled bits and their ordering defined by memcmp().
|
||||
bool operator<(FoldingSetNodeIDRef) const;
|
||||
@ -331,6 +333,9 @@ public:
|
||||
bool operator==(const FoldingSetNodeID &RHS) const;
|
||||
bool operator==(const FoldingSetNodeIDRef RHS) const;
|
||||
|
||||
bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); }
|
||||
bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);}
|
||||
|
||||
/// Used to compare the "ordering" of two nodes as defined by the
|
||||
/// profiled bits and their ordering defined by memcmp().
|
||||
bool operator<(const FoldingSetNodeID &RHS) const;
|
||||
@ -391,20 +396,20 @@ template<class T> class FoldingSet : public FoldingSetImpl {
|
||||
private:
|
||||
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
||||
/// way to convert nodes into a unique specifier.
|
||||
virtual void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const {
|
||||
void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override {
|
||||
T *TN = static_cast<T *>(N);
|
||||
FoldingSetTrait<T>::Profile(*TN, ID);
|
||||
}
|
||||
/// NodeEquals - Instantiations may optionally provide a way to compare a
|
||||
/// node with a specified ID.
|
||||
virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
|
||||
FoldingSetNodeID &TempID) const {
|
||||
bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
|
||||
FoldingSetNodeID &TempID) const override {
|
||||
T *TN = static_cast<T *>(N);
|
||||
return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
|
||||
}
|
||||
/// ComputeNodeHash - Instantiations may optionally provide a way to compute a
|
||||
/// hash value directly from a node.
|
||||
virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const {
|
||||
unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override {
|
||||
T *TN = static_cast<T *>(N);
|
||||
return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
|
||||
}
|
||||
@ -468,20 +473,19 @@ private:
|
||||
|
||||
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
||||
/// way to convert nodes into a unique specifier.
|
||||
virtual void GetNodeProfile(FoldingSetImpl::Node *N,
|
||||
FoldingSetNodeID &ID) const {
|
||||
void GetNodeProfile(FoldingSetImpl::Node *N,
|
||||
FoldingSetNodeID &ID) const override {
|
||||
T *TN = static_cast<T *>(N);
|
||||
ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context);
|
||||
}
|
||||
virtual bool NodeEquals(FoldingSetImpl::Node *N,
|
||||
const FoldingSetNodeID &ID, unsigned IDHash,
|
||||
FoldingSetNodeID &TempID) const {
|
||||
bool NodeEquals(FoldingSetImpl::Node *N, const FoldingSetNodeID &ID,
|
||||
unsigned IDHash, FoldingSetNodeID &TempID) const override {
|
||||
T *TN = static_cast<T *>(N);
|
||||
return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
|
||||
Context);
|
||||
}
|
||||
virtual unsigned ComputeNodeHash(FoldingSetImpl::Node *N,
|
||||
FoldingSetNodeID &TempID) const {
|
||||
unsigned ComputeNodeHash(FoldingSetImpl::Node *N,
|
||||
FoldingSetNodeID &TempID) const override {
|
||||
T *TN = static_cast<T *>(N);
|
||||
return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, Context);
|
||||
}
|
||||
@ -790,6 +794,14 @@ template<typename T> struct FoldingSetTrait<T*> {
|
||||
ID.AddPointer(X);
|
||||
}
|
||||
};
|
||||
template <typename T1, typename T2>
|
||||
struct FoldingSetTrait<std::pair<T1, T2>> {
|
||||
static inline void Profile(const std::pair<T1, T2> &P,
|
||||
llvm::FoldingSetNodeID &ID) {
|
||||
ID.Add(P.first);
|
||||
ID.Add(P.second);
|
||||
}
|
||||
};
|
||||
} // End of namespace llvm.
|
||||
|
||||
#endif
|
||||
|
@ -45,7 +45,6 @@
|
||||
#ifndef LLVM_ADT_HASHING_H
|
||||
#define LLVM_ADT_HASHING_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/SwapByteOrder.h"
|
||||
@ -109,7 +108,8 @@ public:
|
||||
/// differing argument types even if they would implicit promote to a common
|
||||
/// type without changing the value.
|
||||
template <typename T>
|
||||
typename enable_if<is_integral_or_enum<T>, hash_code>::type hash_value(T value);
|
||||
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
|
||||
hash_value(T value);
|
||||
|
||||
/// \brief Compute a hash_code for a pointer's address.
|
||||
///
|
||||
@ -152,7 +152,7 @@ inline uint64_t fetch64(const char *p) {
|
||||
uint64_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
if (sys::IsBigEndianHost)
|
||||
return sys::SwapByteOrder(result);
|
||||
sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ inline uint32_t fetch32(const char *p) {
|
||||
uint32_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
if (sys::IsBigEndianHost)
|
||||
return sys::SwapByteOrder(result);
|
||||
sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -265,7 +265,6 @@ inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
|
||||
/// keeps 56 bytes of arbitrary state.
|
||||
struct hash_state {
|
||||
uint64_t h0, h1, h2, h3, h4, h5, h6;
|
||||
uint64_t seed;
|
||||
|
||||
/// \brief Create a new hash_state structure and initialize it based on the
|
||||
/// seed and the first 64-byte chunk.
|
||||
@ -273,7 +272,7 @@ struct hash_state {
|
||||
static hash_state create(const char *s, uint64_t seed) {
|
||||
hash_state state = {
|
||||
0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
|
||||
seed * k1, shift_mix(seed), 0, seed };
|
||||
seed * k1, shift_mix(seed), 0 };
|
||||
state.h6 = hash_16_bytes(state.h4, state.h5);
|
||||
state.mix(s);
|
||||
return state;
|
||||
@ -352,24 +351,24 @@ inline size_t get_execution_seed() {
|
||||
// and pointers, but there are platforms where it doesn't and we would like to
|
||||
// support user-defined types which happen to satisfy this property.
|
||||
template <typename T> struct is_hashable_data
|
||||
: integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
||||
is_pointer<T>::value) &&
|
||||
64 % sizeof(T) == 0)> {};
|
||||
: std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
||||
std::is_pointer<T>::value) &&
|
||||
64 % sizeof(T) == 0)> {};
|
||||
|
||||
// Special case std::pair to detect when both types are viable and when there
|
||||
// is no alignment-derived padding in the pair. This is a bit of a lie because
|
||||
// std::pair isn't truly POD, but it's close enough in all reasonable
|
||||
// implementations for our use case of hashing the underlying data.
|
||||
template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
||||
: integral_constant<bool, (is_hashable_data<T>::value &&
|
||||
is_hashable_data<U>::value &&
|
||||
(sizeof(T) + sizeof(U)) ==
|
||||
sizeof(std::pair<T, U>))> {};
|
||||
: std::integral_constant<bool, (is_hashable_data<T>::value &&
|
||||
is_hashable_data<U>::value &&
|
||||
(sizeof(T) + sizeof(U)) ==
|
||||
sizeof(std::pair<T, U>))> {};
|
||||
|
||||
/// \brief Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when the type itself can be used.
|
||||
template <typename T>
|
||||
typename enable_if<is_hashable_data<T>, T>::type
|
||||
typename std::enable_if<is_hashable_data<T>::value, T>::type
|
||||
get_hashable_data(const T &value) {
|
||||
return value;
|
||||
}
|
||||
@ -377,7 +376,7 @@ get_hashable_data(const T &value) {
|
||||
/// This variant is enabled when we must first call hash_value and use the
|
||||
/// result as our data.
|
||||
template <typename T>
|
||||
typename enable_if_c<!is_hashable_data<T>::value, size_t>::type
|
||||
typename std::enable_if<!is_hashable_data<T>::value, size_t>::type
|
||||
get_hashable_data(const T &value) {
|
||||
using ::llvm::hash_value;
|
||||
return hash_value(value);
|
||||
@ -411,7 +410,7 @@ template <typename InputIteratorT>
|
||||
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
const size_t seed = get_execution_seed();
|
||||
char buffer[64], *buffer_ptr = buffer;
|
||||
char *const buffer_end = buffer_ptr + array_lengthof(buffer);
|
||||
char *const buffer_end = std::end(buffer);
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
@ -451,7 +450,7 @@ hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
/// are stored in contiguous memory, this routine avoids copying each value
|
||||
/// and directly reads from the underlying memory.
|
||||
template <typename ValueT>
|
||||
typename enable_if<is_hashable_data<ValueT>, hash_code>::type
|
||||
typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
|
||||
hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||
const size_t seed = get_execution_seed();
|
||||
const char *s_begin = reinterpret_cast<const char *>(first);
|
||||
@ -734,7 +733,7 @@ inline hash_code hash_integer_value(uint64_t value) {
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
typename enable_if<is_integral_or_enum<T>, hash_code>::type
|
||||
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
|
||||
hash_value(T value) {
|
||||
return ::llvm::hashing::detail::hash_integer_value(value);
|
||||
}
|
||||
|
@ -1,248 +0,0 @@
|
||||
//===--- ImmutableIntervalMap.h - Immutable (functional) map ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ImmutableIntervalMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_IMMUTABLEINTERVALMAP_H
|
||||
#define LLVM_ADT_IMMUTABLEINTERVALMAP_H
|
||||
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Interval {
|
||||
private:
|
||||
int64_t Start;
|
||||
int64_t End;
|
||||
|
||||
public:
|
||||
Interval(int64_t S, int64_t E) : Start(S), End(E) {}
|
||||
|
||||
int64_t getStart() const { return Start; }
|
||||
int64_t getEnd() const { return End; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ImutIntervalInfo {
|
||||
typedef const std::pair<Interval, T> value_type;
|
||||
typedef const value_type &value_type_ref;
|
||||
typedef const Interval key_type;
|
||||
typedef const Interval &key_type_ref;
|
||||
typedef const T data_type;
|
||||
typedef const T &data_type_ref;
|
||||
|
||||
static key_type_ref KeyOfValue(value_type_ref V) {
|
||||
return V.first;
|
||||
}
|
||||
|
||||
static data_type_ref DataOfValue(value_type_ref V) {
|
||||
return V.second;
|
||||
}
|
||||
|
||||
static bool isEqual(key_type_ref L, key_type_ref R) {
|
||||
return L.getStart() == R.getStart() && L.getEnd() == R.getEnd();
|
||||
}
|
||||
|
||||
static bool isDataEqual(data_type_ref L, data_type_ref R) {
|
||||
return ImutContainerInfo<T>::isEqual(L,R);
|
||||
}
|
||||
|
||||
static bool isLess(key_type_ref L, key_type_ref R) {
|
||||
// Assume L and R does not overlap.
|
||||
if (L.getStart() < R.getStart()) {
|
||||
assert(L.getEnd() < R.getStart());
|
||||
return true;
|
||||
} else if (L.getStart() == R.getStart()) {
|
||||
assert(L.getEnd() == R.getEnd());
|
||||
return false;
|
||||
} else {
|
||||
assert(L.getStart() > R.getEnd());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isContainedIn(key_type_ref K, key_type_ref L) {
|
||||
if (K.getStart() >= L.getStart() && K.getEnd() <= L.getEnd())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Profile(FoldingSetNodeID &ID, value_type_ref V) {
|
||||
ID.AddInteger(V.first.getStart());
|
||||
ID.AddInteger(V.first.getEnd());
|
||||
ImutProfileInfo<T>::Profile(ID, V.second);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ImutInfo>
|
||||
class ImutIntervalAVLFactory : public ImutAVLFactory<ImutInfo> {
|
||||
typedef ImutAVLTree<ImutInfo> TreeTy;
|
||||
typedef typename ImutInfo::value_type value_type;
|
||||
typedef typename ImutInfo::value_type_ref value_type_ref;
|
||||
typedef typename ImutInfo::key_type key_type;
|
||||
typedef typename ImutInfo::key_type_ref key_type_ref;
|
||||
typedef typename ImutInfo::data_type data_type;
|
||||
typedef typename ImutInfo::data_type_ref data_type_ref;
|
||||
|
||||
public:
|
||||
ImutIntervalAVLFactory(BumpPtrAllocator &Alloc)
|
||||
: ImutAVLFactory<ImutInfo>(Alloc) {}
|
||||
|
||||
TreeTy *Add(TreeTy *T, value_type_ref V) {
|
||||
T = add_internal(V,T);
|
||||
this->MarkImmutable(T);
|
||||
return T;
|
||||
}
|
||||
|
||||
TreeTy *Find(TreeTy *T, key_type_ref K) {
|
||||
if (!T)
|
||||
return NULL;
|
||||
|
||||
key_type_ref CurrentKey = ImutInfo::KeyOfValue(this->getValue(T));
|
||||
|
||||
if (ImutInfo::isContainedIn(K, CurrentKey))
|
||||
return T;
|
||||
else if (ImutInfo::isLess(K, CurrentKey))
|
||||
return Find(this->getLeft(T), K);
|
||||
else
|
||||
return Find(this->getRight(T), K);
|
||||
}
|
||||
|
||||
private:
|
||||
TreeTy *add_internal(value_type_ref V, TreeTy *T) {
|
||||
key_type_ref K = ImutInfo::KeyOfValue(V);
|
||||
T = removeAllOverlaps(T, K);
|
||||
if (this->isEmpty(T))
|
||||
return this->CreateNode(NULL, V, NULL);
|
||||
|
||||
assert(!T->isMutable());
|
||||
|
||||
key_type_ref KCurrent = ImutInfo::KeyOfValue(this->Value(T));
|
||||
|
||||
if (ImutInfo::isLess(K, KCurrent))
|
||||
return this->Balance(add_internal(V, this->Left(T)), this->Value(T),
|
||||
this->Right(T));
|
||||
else
|
||||
return this->Balance(this->Left(T), this->Value(T),
|
||||
add_internal(V, this->Right(T)));
|
||||
}
|
||||
|
||||
// Remove all overlaps from T.
|
||||
TreeTy *removeAllOverlaps(TreeTy *T, key_type_ref K) {
|
||||
bool Changed;
|
||||
do {
|
||||
Changed = false;
|
||||
T = removeOverlap(T, K, Changed);
|
||||
this->markImmutable(T);
|
||||
} while (Changed);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
// Remove one overlap from T.
|
||||
TreeTy *removeOverlap(TreeTy *T, key_type_ref K, bool &Changed) {
|
||||
if (!T)
|
||||
return NULL;
|
||||
Interval CurrentK = ImutInfo::KeyOfValue(this->Value(T));
|
||||
|
||||
// If current key does not overlap the inserted key.
|
||||
if (CurrentK.getStart() > K.getEnd())
|
||||
return this->Balance(removeOverlap(this->Left(T), K, Changed),
|
||||
this->Value(T), this->Right(T));
|
||||
else if (CurrentK.getEnd() < K.getStart())
|
||||
return this->Balance(this->Left(T), this->Value(T),
|
||||
removeOverlap(this->Right(T), K, Changed));
|
||||
|
||||
// Current key overlaps with the inserted key.
|
||||
// Remove the current key.
|
||||
Changed = true;
|
||||
data_type_ref OldData = ImutInfo::DataOfValue(this->Value(T));
|
||||
T = this->Remove_internal(CurrentK, T);
|
||||
// Add back the unoverlapped part of the current key.
|
||||
if (CurrentK.getStart() < K.getStart()) {
|
||||
if (CurrentK.getEnd() <= K.getEnd()) {
|
||||
Interval NewK(CurrentK.getStart(), K.getStart()-1);
|
||||
return add_internal(std::make_pair(NewK, OldData), T);
|
||||
} else {
|
||||
Interval NewK1(CurrentK.getStart(), K.getStart()-1);
|
||||
T = add_internal(std::make_pair(NewK1, OldData), T);
|
||||
|
||||
Interval NewK2(K.getEnd()+1, CurrentK.getEnd());
|
||||
return add_internal(std::make_pair(NewK2, OldData), T);
|
||||
}
|
||||
} else {
|
||||
if (CurrentK.getEnd() > K.getEnd()) {
|
||||
Interval NewK(K.getEnd()+1, CurrentK.getEnd());
|
||||
return add_internal(std::make_pair(NewK, OldData), T);
|
||||
} else
|
||||
return T;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// ImmutableIntervalMap maps an interval [start, end] to a value. The intervals
|
||||
/// in the map are guaranteed to be disjoint.
|
||||
template <typename ValT>
|
||||
class ImmutableIntervalMap
|
||||
: public ImmutableMap<Interval, ValT, ImutIntervalInfo<ValT> > {
|
||||
|
||||
typedef typename ImutIntervalInfo<ValT>::value_type value_type;
|
||||
typedef typename ImutIntervalInfo<ValT>::value_type_ref value_type_ref;
|
||||
typedef typename ImutIntervalInfo<ValT>::key_type key_type;
|
||||
typedef typename ImutIntervalInfo<ValT>::key_type_ref key_type_ref;
|
||||
typedef typename ImutIntervalInfo<ValT>::data_type data_type;
|
||||
typedef typename ImutIntervalInfo<ValT>::data_type_ref data_type_ref;
|
||||
typedef ImutAVLTree<ImutIntervalInfo<ValT> > TreeTy;
|
||||
|
||||
public:
|
||||
explicit ImmutableIntervalMap(TreeTy *R)
|
||||
: ImmutableMap<Interval, ValT, ImutIntervalInfo<ValT> >(R) {}
|
||||
|
||||
class Factory {
|
||||
ImutIntervalAVLFactory<ImutIntervalInfo<ValT> > F;
|
||||
|
||||
public:
|
||||
Factory(BumpPtrAllocator& Alloc) : F(Alloc) {}
|
||||
|
||||
ImmutableIntervalMap getEmptyMap() {
|
||||
return ImmutableIntervalMap(F.getEmptyTree());
|
||||
}
|
||||
|
||||
ImmutableIntervalMap add(ImmutableIntervalMap Old,
|
||||
key_type_ref K, data_type_ref D) {
|
||||
TreeTy *T = F.add(Old.Root, std::pair<key_type, data_type>(K, D));
|
||||
return ImmutableIntervalMap(F.getCanonicalTree(T));
|
||||
}
|
||||
|
||||
ImmutableIntervalMap remove(ImmutableIntervalMap Old, key_type_ref K) {
|
||||
TreeTy *T = F.remove(Old.Root, K);
|
||||
return ImmutableIntervalMap(F.getCanonicalTree(T));
|
||||
}
|
||||
|
||||
data_type *lookup(ImmutableIntervalMap M, key_type_ref K) {
|
||||
TreeTy *T = F.Find(M.getRoot(), K);
|
||||
if (T)
|
||||
return &T->getValue().second;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// For ImmutableIntervalMap, the lookup operation has to be done by the
|
||||
// factory.
|
||||
data_type* lookup(key_type_ref K) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -241,14 +241,14 @@ public:
|
||||
if (T) return &T->getValue().second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
|
||||
/// which key is the highest in the ordering of keys in the map. This
|
||||
/// method returns NULL if the map is empty.
|
||||
value_type* getMaxElement() const {
|
||||
return Root ? &(Root->getMaxElement()->getValue()) : 0;
|
||||
return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------===//
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
else
|
||||
T = T->getRight();
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getMaxElement - Find the subtree associated with the highest ranged
|
||||
@ -242,9 +242,9 @@ private:
|
||||
/// ImutAVLFactory.
|
||||
ImutAVLTree(Factory *f, ImutAVLTree* l, ImutAVLTree* r, value_type_ref v,
|
||||
unsigned height)
|
||||
: factory(f), left(l), right(r), prev(0), next(0), height(height),
|
||||
IsMutable(true), IsDigestCached(false), IsCanonicalized(0),
|
||||
value(v), digest(0), refCount(0)
|
||||
: factory(f), left(l), right(r), prev(nullptr), next(nullptr),
|
||||
height(height), IsMutable(true), IsDigestCached(false),
|
||||
IsCanonicalized(0), value(v), digest(0), refCount(0)
|
||||
{
|
||||
if (left) left->retain();
|
||||
if (right) right->retain();
|
||||
@ -411,7 +411,7 @@ public:
|
||||
return T;
|
||||
}
|
||||
|
||||
TreeTy* getEmptyTree() const { return NULL; }
|
||||
TreeTy* getEmptyTree() const { return nullptr; }
|
||||
|
||||
protected:
|
||||
|
||||
@ -607,7 +607,7 @@ protected:
|
||||
public:
|
||||
TreeTy *getCanonicalTree(TreeTy *TNew) {
|
||||
if (!TNew)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
if (TNew->IsCanonicalized)
|
||||
return TNew;
|
||||
@ -619,7 +619,7 @@ public:
|
||||
do {
|
||||
if (!entry)
|
||||
break;
|
||||
for (TreeTy *T = entry ; T != 0; T = T->next) {
|
||||
for (TreeTy *T = entry ; T != nullptr; T = T->next) {
|
||||
// Compare the Contents('T') with Contents('TNew')
|
||||
typename TreeTy::iterator TI = T->begin(), TE = T->end();
|
||||
if (!compareTreeWithSection(TNew, TI, TE))
|
||||
@ -696,12 +696,7 @@ public:
|
||||
}
|
||||
|
||||
inline bool operator==(const _Self& x) const {
|
||||
if (stack.size() != x.stack.size())
|
||||
return false;
|
||||
for (unsigned i = 0 ; i < stack.size(); i++)
|
||||
if (stack[i] != x.stack[i])
|
||||
return false;
|
||||
return true;
|
||||
return stack == x.stack;
|
||||
}
|
||||
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
|
@ -1177,7 +1177,7 @@ branchRoot(unsigned Position) {
|
||||
if (Nodes == 1)
|
||||
size[0] = rootSize;
|
||||
else
|
||||
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, NULL, size,
|
||||
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, nullptr, size,
|
||||
Position, true);
|
||||
|
||||
// Allocate new nodes.
|
||||
@ -1218,7 +1218,7 @@ splitRoot(unsigned Position) {
|
||||
if (Nodes == 1)
|
||||
Size[0] = rootSize;
|
||||
else
|
||||
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, NULL, Size,
|
||||
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, nullptr, Size,
|
||||
Position, true);
|
||||
|
||||
// Allocate new nodes.
|
||||
@ -1346,7 +1346,7 @@ protected:
|
||||
|
||||
public:
|
||||
/// const_iterator - Create an iterator that isn't pointing anywhere.
|
||||
const_iterator() : map(0) {}
|
||||
const_iterator() : map(nullptr) {}
|
||||
|
||||
/// setMap - Change the map iterated over. This call must be followed by a
|
||||
/// call to goToBegin(), goToEnd(), or find()
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
@ -88,6 +89,31 @@ namespace llvm {
|
||||
static void retain(T *obj) { obj->Retain(); }
|
||||
static void release(T *obj) { obj->Release(); }
|
||||
};
|
||||
|
||||
/// \brief A thread-safe version of \c llvm::RefCountedBase.
|
||||
///
|
||||
/// A generic base class for objects that wish to have their lifetimes managed
|
||||
/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
|
||||
/// obtain such functionality, and are typically handled with
|
||||
/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
|
||||
/// management of reference counts.
|
||||
template <class Derived>
|
||||
class ThreadSafeRefCountedBase {
|
||||
mutable std::atomic<int> RefCount;
|
||||
|
||||
protected:
|
||||
ThreadSafeRefCountedBase() : RefCount(0) {}
|
||||
|
||||
public:
|
||||
void Retain() const { ++RefCount; }
|
||||
|
||||
void Release() const {
|
||||
int NewRefCount = --RefCount;
|
||||
assert(NewRefCount >= 0 && "Reference count was already zero.");
|
||||
if (NewRefCount == 0)
|
||||
delete static_cast<const Derived*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
|
||||
@ -109,11 +135,11 @@ namespace llvm {
|
||||
template <typename T>
|
||||
class IntrusiveRefCntPtr {
|
||||
T* Obj;
|
||||
typedef IntrusiveRefCntPtr this_type;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
explicit IntrusiveRefCntPtr() : Obj(0) {}
|
||||
explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
|
||||
|
||||
IntrusiveRefCntPtr(T* obj) : Obj(obj) {
|
||||
retain();
|
||||
@ -123,20 +149,18 @@ namespace llvm {
|
||||
retain();
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
|
||||
S.Obj = 0;
|
||||
S.Obj = nullptr;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.getPtr()) {
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
|
||||
S.Obj = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
|
||||
: Obj(S.getPtr()) {
|
||||
: Obj(S.get()) {
|
||||
retain();
|
||||
}
|
||||
|
||||
@ -151,12 +175,9 @@ namespace llvm {
|
||||
|
||||
T* operator->() const { return Obj; }
|
||||
|
||||
T* getPtr() const { return Obj; }
|
||||
T* get() const { return Obj; }
|
||||
|
||||
typedef T* (IntrusiveRefCntPtr::*unspecified_bool_type) () const;
|
||||
operator unspecified_bool_type() const {
|
||||
return Obj == 0 ? 0 : &IntrusiveRefCntPtr::getPtr;
|
||||
}
|
||||
LLVM_EXPLICIT operator bool() const { return Obj; }
|
||||
|
||||
void swap(IntrusiveRefCntPtr& other) {
|
||||
T* tmp = other.Obj;
|
||||
@ -166,7 +187,7 @@ namespace llvm {
|
||||
|
||||
void reset() {
|
||||
release();
|
||||
Obj = 0;
|
||||
Obj = nullptr;
|
||||
}
|
||||
|
||||
void resetWithoutRelease() {
|
||||
@ -182,42 +203,62 @@ namespace llvm {
|
||||
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A.getPtr() == B.getPtr();
|
||||
return A.get() == B.get();
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A.getPtr() != B.getPtr();
|
||||
return A.get() != B.get();
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
||||
U* B)
|
||||
{
|
||||
return A.getPtr() == B;
|
||||
return A.get() == B;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
||||
U* B)
|
||||
{
|
||||
return A.getPtr() != B;
|
||||
return A.get() != B;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(T* A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A == B.getPtr();
|
||||
return A == B.get();
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator!=(T* A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A != B.getPtr();
|
||||
return A != B.get();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
|
||||
return !B;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
|
||||
return B == A;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
|
||||
return !(A == B);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
|
||||
return !(A == B);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -227,14 +268,14 @@ namespace llvm {
|
||||
template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
|
||||
typedef T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
|
||||
return Val.getPtr();
|
||||
return Val.get();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
|
||||
typedef /*const*/ T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
|
||||
return Val.getPtr();
|
||||
return Val.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- llvm/ADT/MapVector.h - Map with deterministic value order *- C++ -*-===//
|
||||
//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -17,9 +17,7 @@
|
||||
#ifndef LLVM_ADT_MAPVECTOR_H
|
||||
#define LLVM_ADT_MAPVECTOR_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -31,7 +29,7 @@ template<typename KeyT, typename ValueT,
|
||||
typename MapType = llvm::DenseMap<KeyT, unsigned>,
|
||||
typename VectorType = std::vector<std::pair<KeyT, ValueT> > >
|
||||
class MapVector {
|
||||
typedef typename VectorType::size_type SizeType;
|
||||
typedef typename VectorType::size_type size_type;
|
||||
|
||||
MapType Map;
|
||||
VectorType Vector;
|
||||
@ -40,7 +38,7 @@ public:
|
||||
typedef typename VectorType::iterator iterator;
|
||||
typedef typename VectorType::const_iterator const_iterator;
|
||||
|
||||
SizeType size() const {
|
||||
size_type size() const {
|
||||
return Vector.size();
|
||||
}
|
||||
|
||||
@ -97,12 +95,12 @@ public:
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::make_pair(KV.first, KV.second));
|
||||
I = Vector.size() - 1;
|
||||
return std::make_pair(llvm::prior(end()), true);
|
||||
return std::make_pair(std::prev(end()), true);
|
||||
}
|
||||
return std::make_pair(begin() + I, false);
|
||||
}
|
||||
|
||||
unsigned count(const KeyT &Key) const {
|
||||
size_type count(const KeyT &Key) const {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? 0 : 1;
|
||||
}
|
||||
@ -125,8 +123,59 @@ public:
|
||||
Map.erase(Pos);
|
||||
Vector.pop_back();
|
||||
}
|
||||
|
||||
/// \brief Remove the element given by Iterator.
|
||||
///
|
||||
/// Returns an iterator to the element following the one which was removed,
|
||||
/// which may be end().
|
||||
///
|
||||
/// \note This is a deceivingly expensive operation (linear time). It's
|
||||
/// usually better to use \a remove_if() if possible.
|
||||
typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
|
||||
Map.erase(Iterator->first);
|
||||
auto Next = Vector.erase(Iterator);
|
||||
if (Next == Vector.end())
|
||||
return Next;
|
||||
|
||||
// Update indices in the map.
|
||||
size_t Index = Next - Vector.begin();
|
||||
for (auto &I : Map) {
|
||||
assert(I.second != Index && "Index was already erased!");
|
||||
if (I.second > Index)
|
||||
--I.second;
|
||||
}
|
||||
return Next;
|
||||
}
|
||||
|
||||
/// \brief Remove the elements that match the predicate.
|
||||
///
|
||||
/// Erase all elements that match \c Pred in a single pass. Takes linear
|
||||
/// time.
|
||||
template <class Predicate> void remove_if(Predicate Pred);
|
||||
};
|
||||
|
||||
template <typename KeyT, typename ValueT, typename MapType, typename VectorType>
|
||||
template <class Function>
|
||||
void MapVector<KeyT, ValueT, MapType, VectorType>::remove_if(Function Pred) {
|
||||
auto O = Vector.begin();
|
||||
for (auto I = O, E = Vector.end(); I != E; ++I) {
|
||||
if (Pred(*I)) {
|
||||
// Erase from the map.
|
||||
Map.erase(I->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (I != O) {
|
||||
// Move the value and update the index in the map.
|
||||
*O = std::move(*I);
|
||||
Map[O->first] = O - Vector.begin();
|
||||
}
|
||||
++O;
|
||||
}
|
||||
// Erase trailing entries in the vector.
|
||||
Vector.erase(O, Vector.end());
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -17,13 +17,10 @@
|
||||
#define LLVM_ADT_OPTIONAL_H
|
||||
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cassert>
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -42,7 +39,6 @@ public:
|
||||
new (storage.buffer) T(*O);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
Optional(T &&y) : hasVal(true) {
|
||||
new (storage.buffer) T(std::forward<T>(y));
|
||||
}
|
||||
@ -70,7 +66,6 @@ public:
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline Optional create(const T* y) {
|
||||
return y ? Optional(*y) : Optional();
|
||||
|
@ -1,153 +0,0 @@
|
||||
//===- llvm/ADT/OwningPtr.h - Smart ptr that owns the pointee ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines and implements the OwningPtr class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_OWNINGPTR_H
|
||||
#define LLVM_ADT_OWNINGPTR_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// OwningPtr smart pointer - OwningPtr mimics a built-in pointer except that it
|
||||
/// guarantees deletion of the object pointed to, either on destruction of the
|
||||
/// OwningPtr or via an explicit reset(). Once created, ownership of the
|
||||
/// pointee object can be taken away from OwningPtr by using the take method.
|
||||
template<class T>
|
||||
class OwningPtr {
|
||||
OwningPtr(OwningPtr const &) LLVM_DELETED_FUNCTION;
|
||||
OwningPtr &operator=(OwningPtr const &) LLVM_DELETED_FUNCTION;
|
||||
T *Ptr;
|
||||
public:
|
||||
explicit OwningPtr(T *P = 0) : Ptr(P) {}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
OwningPtr(OwningPtr &&Other) : Ptr(Other.take()) {}
|
||||
|
||||
OwningPtr &operator=(OwningPtr &&Other) {
|
||||
reset(Other.take());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
~OwningPtr() {
|
||||
delete Ptr;
|
||||
}
|
||||
|
||||
/// reset - Change the current pointee to the specified pointer. Note that
|
||||
/// calling this with any pointer (including a null pointer) deletes the
|
||||
/// current pointer.
|
||||
void reset(T *P = 0) {
|
||||
if (P == Ptr) return;
|
||||
T *Tmp = Ptr;
|
||||
Ptr = P;
|
||||
delete Tmp;
|
||||
}
|
||||
|
||||
/// take - Reset the owning pointer to null and return its pointer. This does
|
||||
/// not delete the pointer before returning it.
|
||||
T *take() {
|
||||
T *Tmp = Ptr;
|
||||
Ptr = 0;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
T &operator*() const {
|
||||
assert(Ptr && "Cannot dereference null pointer");
|
||||
return *Ptr;
|
||||
}
|
||||
|
||||
T *operator->() const { return Ptr; }
|
||||
T *get() const { return Ptr; }
|
||||
LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
|
||||
bool operator!() const { return Ptr == 0; }
|
||||
bool isValid() const { return Ptr != 0; }
|
||||
|
||||
void swap(OwningPtr &RHS) {
|
||||
T *Tmp = RHS.Ptr;
|
||||
RHS.Ptr = Ptr;
|
||||
Ptr = Tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline void swap(OwningPtr<T> &a, OwningPtr<T> &b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
/// OwningArrayPtr smart pointer - OwningArrayPtr provides the same
|
||||
/// functionality as OwningPtr, except that it works for array types.
|
||||
template<class T>
|
||||
class OwningArrayPtr {
|
||||
OwningArrayPtr(OwningArrayPtr const &) LLVM_DELETED_FUNCTION;
|
||||
OwningArrayPtr &operator=(OwningArrayPtr const &) LLVM_DELETED_FUNCTION;
|
||||
T *Ptr;
|
||||
public:
|
||||
explicit OwningArrayPtr(T *P = 0) : Ptr(P) {}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
OwningArrayPtr(OwningArrayPtr &&Other) : Ptr(Other.take()) {}
|
||||
|
||||
OwningArrayPtr &operator=(OwningArrayPtr &&Other) {
|
||||
reset(Other.take());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
~OwningArrayPtr() {
|
||||
delete [] Ptr;
|
||||
}
|
||||
|
||||
/// reset - Change the current pointee to the specified pointer. Note that
|
||||
/// calling this with any pointer (including a null pointer) deletes the
|
||||
/// current pointer.
|
||||
void reset(T *P = 0) {
|
||||
if (P == Ptr) return;
|
||||
T *Tmp = Ptr;
|
||||
Ptr = P;
|
||||
delete [] Tmp;
|
||||
}
|
||||
|
||||
/// take - Reset the owning pointer to null and return its pointer. This does
|
||||
/// not delete the pointer before returning it.
|
||||
T *take() {
|
||||
T *Tmp = Ptr;
|
||||
Ptr = 0;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
T &operator[](std::ptrdiff_t i) const {
|
||||
assert(Ptr && "Cannot dereference null pointer");
|
||||
return Ptr[i];
|
||||
}
|
||||
|
||||
T *get() const { return Ptr; }
|
||||
LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
|
||||
bool operator!() const { return Ptr == 0; }
|
||||
|
||||
void swap(OwningArrayPtr &RHS) {
|
||||
T *Tmp = RHS.Ptr;
|
||||
RHS.Ptr = Ptr;
|
||||
Ptr = Tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline void swap(OwningArrayPtr<T> &a, OwningArrayPtr<T> &b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -41,7 +42,12 @@ template <typename PointerTy, unsigned IntBits, typename IntType=unsigned,
|
||||
typename PtrTraits = PointerLikeTypeTraits<PointerTy> >
|
||||
class PointerIntPair {
|
||||
intptr_t Value;
|
||||
enum LLVM_ENUM_INT_TYPE(uintptr_t) {
|
||||
static_assert(PtrTraits::NumLowBitsAvailable <
|
||||
std::numeric_limits<uintptr_t>::digits,
|
||||
"cannot use a pointer type that has all bits free");
|
||||
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
|
||||
"PointerIntPair with integer size too large for pointer");
|
||||
enum : uintptr_t {
|
||||
/// PointerBitMask - The bits that come from the pointer.
|
||||
PointerBitMask =
|
||||
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable)-1),
|
||||
@ -59,8 +65,6 @@ class PointerIntPair {
|
||||
public:
|
||||
PointerIntPair() : Value(0) {}
|
||||
PointerIntPair(PointerTy PtrVal, IntType IntVal) {
|
||||
assert(IntBits <= PtrTraits::NumLowBitsAvailable &&
|
||||
"PointerIntPair formed with integer size too large for pointer");
|
||||
setPointerAndInt(PtrVal, IntVal);
|
||||
}
|
||||
explicit PointerIntPair(PointerTy PtrVal) {
|
||||
@ -79,7 +83,7 @@ public:
|
||||
void setPointer(PointerTy PtrVal) {
|
||||
intptr_t PtrWord
|
||||
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
||||
assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
|
||||
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||
"Pointer is not sufficiently aligned");
|
||||
// Preserve all low bits, just update the pointer.
|
||||
Value = PtrWord | (Value & ~PointerBitMask);
|
||||
@ -87,7 +91,7 @@ public:
|
||||
|
||||
void setInt(IntType IntVal) {
|
||||
intptr_t IntWord = static_cast<intptr_t>(IntVal);
|
||||
assert(IntWord < (1 << IntBits) && "Integer too large for field");
|
||||
assert((IntWord & ~IntMask) == 0 && "Integer too large for field");
|
||||
|
||||
// Preserve all bits other than the ones we are updating.
|
||||
Value &= ~ShiftedIntMask; // Remove integer field.
|
||||
@ -97,7 +101,7 @@ public:
|
||||
void initWithPointer(PointerTy PtrVal) {
|
||||
intptr_t PtrWord
|
||||
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
||||
assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
|
||||
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||
"Pointer is not sufficiently aligned");
|
||||
Value = PtrWord;
|
||||
}
|
||||
@ -105,10 +109,10 @@ public:
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
|
||||
intptr_t PtrWord
|
||||
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
||||
assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
|
||||
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||
"Pointer is not sufficiently aligned");
|
||||
intptr_t IntWord = static_cast<intptr_t>(IntVal);
|
||||
assert(IntWord < (1 << IntBits) && "Integer too large for field");
|
||||
assert((IntWord & ~IntMask) == 0 && "Integer too large for field");
|
||||
|
||||
Value = PtrWord | (IntWord << IntShift);
|
||||
}
|
||||
@ -158,13 +162,13 @@ struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType> > {
|
||||
typedef PointerIntPair<PointerTy, IntBits, IntType> Ty;
|
||||
static Ty getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
||||
return Ty(reinterpret_cast<PointerTy>(Val), IntType((1 << IntBits)-1));
|
||||
Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable;
|
||||
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||
}
|
||||
static Ty getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
||||
return Ty(reinterpret_cast<PointerTy>(Val), IntType(0));
|
||||
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||
}
|
||||
static unsigned getHashValue(Ty V) {
|
||||
uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue());
|
||||
|
@ -15,8 +15,9 @@
|
||||
#ifndef LLVM_ADT_POINTERUNION_H
|
||||
#define LLVM_ADT_POINTERUNION_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -153,6 +154,12 @@ namespace llvm {
|
||||
"Can't get the address because PointerLikeTypeTraits changes the ptr");
|
||||
return (PT1 *)Val.getAddrOfPointer();
|
||||
}
|
||||
|
||||
/// \brief Assignment from nullptr which just clears the union.
|
||||
const PointerUnion &operator=(std::nullptr_t) {
|
||||
Val.initWithPointer(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assignment operators - Allow assigning into this union from either
|
||||
/// pointer type, setting the discriminator to remember what it came from.
|
||||
@ -297,6 +304,12 @@ namespace llvm {
|
||||
if (is<T>()) return get<T>();
|
||||
return T();
|
||||
}
|
||||
|
||||
/// \brief Assignment from nullptr which just clears the union.
|
||||
const PointerUnion3 &operator=(std::nullptr_t) {
|
||||
Val = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assignment operators - Allow assigning into this union from either
|
||||
/// pointer type, setting the discriminator to remember what it came from.
|
||||
@ -406,6 +419,12 @@ namespace llvm {
|
||||
if (is<T>()) return get<T>();
|
||||
return T();
|
||||
}
|
||||
|
||||
/// \brief Assignment from nullptr which just clears the union.
|
||||
const PointerUnion4 &operator=(std::nullptr_t) {
|
||||
Val = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assignment operators - Allow assigning into this union from either
|
||||
/// pointer type, setting the discriminator to remember what it came from.
|
||||
@ -455,6 +474,33 @@ namespace llvm {
|
||||
::NumLowBitsAvailable
|
||||
};
|
||||
};
|
||||
|
||||
// Teach DenseMap how to use PointerUnions as keys.
|
||||
template<typename T, typename U>
|
||||
struct DenseMapInfo<PointerUnion<T, U> > {
|
||||
typedef PointerUnion<T, U> Pair;
|
||||
typedef DenseMapInfo<T> FirstInfo;
|
||||
typedef DenseMapInfo<U> SecondInfo;
|
||||
|
||||
static inline Pair getEmptyKey() {
|
||||
return Pair(FirstInfo::getEmptyKey());
|
||||
}
|
||||
static inline Pair getTombstoneKey() {
|
||||
return Pair(FirstInfo::getTombstoneKey());
|
||||
}
|
||||
static unsigned getHashValue(const Pair &PairVal) {
|
||||
intptr_t key = (intptr_t)PairVal.getOpaqueValue();
|
||||
return DenseMapInfo<intptr_t>::getHashValue(key);
|
||||
}
|
||||
static bool isEqual(const Pair &LHS, const Pair &RHS) {
|
||||
return LHS.template is<T>() == RHS.template is<T>() &&
|
||||
(LHS.template is<T>() ?
|
||||
FirstInfo::isEqual(LHS.template get<T>(),
|
||||
RHS.template get<T>()) :
|
||||
SecondInfo::isEqual(LHS.template get<U>(),
|
||||
RHS.template get<U>()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -111,7 +111,7 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
}
|
||||
|
||||
inline po_iterator(NodeType *BB) {
|
||||
this->insertEdge((NodeType*)0, BB);
|
||||
this->insertEdge((NodeType*)nullptr, BB);
|
||||
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||
traverseChild();
|
||||
}
|
||||
@ -119,7 +119,7 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
|
||||
inline po_iterator(NodeType *BB, SetType &S) :
|
||||
po_iterator_storage<SetType, ExtStorage>(S) {
|
||||
if (this->insertEdge((NodeType*)0, BB)) {
|
||||
if (this->insertEdge((NodeType*)nullptr, BB)) {
|
||||
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||
traverseChild();
|
||||
}
|
||||
|
@ -6,16 +6,18 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected
|
||||
// components (SCCs) of a graph in O(N+E) time using Tarjan's DFS algorithm.
|
||||
//
|
||||
// The SCC iterator has the important property that if a node in SCC S1 has an
|
||||
// edge to a node in SCC S2, then it visits S1 *after* S2.
|
||||
//
|
||||
// To visit S1 *before* S2, use the scc_iterator on the Inverse graph.
|
||||
// (NOTE: This requires some simple wrappers and is not supported yet.)
|
||||
//
|
||||
/// \file
|
||||
///
|
||||
/// This builds on the llvm/ADT/GraphTraits.h file to find the strongly
|
||||
/// connected components (SCCs) of a graph in O(N+E) time using Tarjan's DFS
|
||||
/// algorithm.
|
||||
///
|
||||
/// The SCC iterator has the important property that if a node in SCC S1 has an
|
||||
/// edge to a node in SCC S2, then it visits S1 *after* S2.
|
||||
///
|
||||
/// To visit S1 *before* S2, use the scc_iterator on the Inverse graph. (NOTE:
|
||||
/// This requires some simple wrappers and is not supported yet.)
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SCCITERATOR_H
|
||||
@ -23,169 +25,112 @@
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \brief Enumerate the SCCs of a directed graph in reverse topological order
|
||||
/// of the SCC DAG.
|
||||
///
|
||||
/// scc_iterator - Enumerate the SCCs of a directed graph, in
|
||||
/// reverse topological order of the SCC DAG.
|
||||
///
|
||||
template<class GraphT, class GT = GraphTraits<GraphT> >
|
||||
/// This is implemented using Tarjan's DFS algorithm using an internal stack to
|
||||
/// build up a vector of nodes in a particular SCC. Note that it is a forward
|
||||
/// iterator and thus you cannot backtrack or re-visit nodes.
|
||||
template <class GraphT, class GT = GraphTraits<GraphT>>
|
||||
class scc_iterator
|
||||
: public std::iterator<std::forward_iterator_tag,
|
||||
std::vector<typename GT::NodeType>, ptrdiff_t> {
|
||||
typedef typename GT::NodeType NodeType;
|
||||
: public iterator_facade_base<
|
||||
scc_iterator<GraphT, GT>, std::forward_iterator_tag,
|
||||
const std::vector<typename GT::NodeType *>, ptrdiff_t> {
|
||||
typedef typename GT::NodeType NodeType;
|
||||
typedef typename GT::ChildIteratorType ChildItTy;
|
||||
typedef std::vector<NodeType*> SccTy;
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
std::vector<typename GT::NodeType>, ptrdiff_t> super;
|
||||
typedef typename super::reference reference;
|
||||
typedef typename super::pointer pointer;
|
||||
typedef std::vector<NodeType *> SccTy;
|
||||
typedef typename scc_iterator::reference reference;
|
||||
|
||||
// The visit counters used to detect when a complete SCC is on the stack.
|
||||
// visitNum is the global counter.
|
||||
// nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
|
||||
/// Element of VisitStack during DFS.
|
||||
struct StackElement {
|
||||
NodeType *Node; ///< The current node pointer.
|
||||
ChildItTy NextChild; ///< The next child, modified inplace during DFS.
|
||||
unsigned MinVisited; ///< Minimum uplink value of all children of Node.
|
||||
|
||||
StackElement(NodeType *Node, const ChildItTy &Child, unsigned Min)
|
||||
: Node(Node), NextChild(Child), MinVisited(Min) {}
|
||||
|
||||
bool operator==(const StackElement &Other) const {
|
||||
return Node == Other.Node &&
|
||||
NextChild == Other.NextChild &&
|
||||
MinVisited == Other.MinVisited;
|
||||
}
|
||||
};
|
||||
|
||||
/// The visit counters used to detect when a complete SCC is on the stack.
|
||||
/// visitNum is the global counter.
|
||||
///
|
||||
/// nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
|
||||
unsigned visitNum;
|
||||
DenseMap<NodeType *, unsigned> nodeVisitNumbers;
|
||||
|
||||
// SCCNodeStack - Stack holding nodes of the SCC.
|
||||
/// Stack holding nodes of the SCC.
|
||||
std::vector<NodeType *> SCCNodeStack;
|
||||
|
||||
// CurrentSCC - The current SCC, retrieved using operator*().
|
||||
/// The current SCC, retrieved using operator*().
|
||||
SccTy CurrentSCC;
|
||||
|
||||
// VisitStack - Used to maintain the ordering. Top = current block
|
||||
// First element is basic block pointer, second is the 'next child' to visit
|
||||
std::vector<std::pair<NodeType *, ChildItTy> > VisitStack;
|
||||
/// DFS stack, Used to maintain the ordering. The top contains the current
|
||||
/// node, the next child to visit, and the minimum uplink value of all child
|
||||
std::vector<StackElement> VisitStack;
|
||||
|
||||
// MinVisitNumStack - Stack holding the "min" values for each node in the DFS.
|
||||
// This is used to track the minimum uplink values for all children of
|
||||
// the corresponding node on the VisitStack.
|
||||
std::vector<unsigned> MinVisitNumStack;
|
||||
/// A single "visit" within the non-recursive DFS traversal.
|
||||
void DFSVisitOne(NodeType *N);
|
||||
|
||||
// A single "visit" within the non-recursive DFS traversal.
|
||||
void DFSVisitOne(NodeType *N) {
|
||||
++visitNum; // Global counter for the visit order
|
||||
nodeVisitNumbers[N] = visitNum;
|
||||
SCCNodeStack.push_back(N);
|
||||
MinVisitNumStack.push_back(visitNum);
|
||||
VisitStack.push_back(std::make_pair(N, GT::child_begin(N)));
|
||||
//dbgs() << "TarjanSCC: Node " << N <<
|
||||
// " : visitNum = " << visitNum << "\n";
|
||||
}
|
||||
/// The stack-based DFS traversal; defined below.
|
||||
void DFSVisitChildren();
|
||||
|
||||
// The stack-based DFS traversal; defined below.
|
||||
void DFSVisitChildren() {
|
||||
assert(!VisitStack.empty());
|
||||
while (VisitStack.back().second != GT::child_end(VisitStack.back().first)) {
|
||||
// TOS has at least one more child so continue DFS
|
||||
NodeType *childN = *VisitStack.back().second++;
|
||||
if (!nodeVisitNumbers.count(childN)) {
|
||||
// this node has never been seen.
|
||||
DFSVisitOne(childN);
|
||||
continue;
|
||||
}
|
||||
/// Compute the next SCC using the DFS traversal.
|
||||
void GetNextSCC();
|
||||
|
||||
unsigned childNum = nodeVisitNumbers[childN];
|
||||
if (MinVisitNumStack.back() > childNum)
|
||||
MinVisitNumStack.back() = childNum;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the next SCC using the DFS traversal.
|
||||
void GetNextSCC() {
|
||||
assert(VisitStack.size() == MinVisitNumStack.size());
|
||||
CurrentSCC.clear(); // Prepare to compute the next SCC
|
||||
while (!VisitStack.empty()) {
|
||||
DFSVisitChildren();
|
||||
assert(VisitStack.back().second ==GT::child_end(VisitStack.back().first));
|
||||
NodeType *visitingN = VisitStack.back().first;
|
||||
unsigned minVisitNum = MinVisitNumStack.back();
|
||||
VisitStack.pop_back();
|
||||
MinVisitNumStack.pop_back();
|
||||
if (!MinVisitNumStack.empty() && MinVisitNumStack.back() > minVisitNum)
|
||||
MinVisitNumStack.back() = minVisitNum;
|
||||
|
||||
//dbgs() << "TarjanSCC: Popped node " << visitingN <<
|
||||
// " : minVisitNum = " << minVisitNum << "; Node visit num = " <<
|
||||
// nodeVisitNumbers[visitingN] << "\n";
|
||||
|
||||
if (minVisitNum != nodeVisitNumbers[visitingN])
|
||||
continue;
|
||||
|
||||
// A full SCC is on the SCCNodeStack! It includes all nodes below
|
||||
// visitingN on the stack. Copy those nodes to CurrentSCC,
|
||||
// reset their minVisit values, and return (this suspends
|
||||
// the DFS traversal till the next ++).
|
||||
do {
|
||||
CurrentSCC.push_back(SCCNodeStack.back());
|
||||
SCCNodeStack.pop_back();
|
||||
nodeVisitNumbers[CurrentSCC.back()] = ~0U;
|
||||
} while (CurrentSCC.back() != visitingN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inline scc_iterator(NodeType *entryN) : visitNum(0) {
|
||||
scc_iterator(NodeType *entryN) : visitNum(0) {
|
||||
DFSVisitOne(entryN);
|
||||
GetNextSCC();
|
||||
}
|
||||
inline scc_iterator() { /* End is when DFS stack is empty */ }
|
||||
|
||||
/// End is when the DFS stack is empty.
|
||||
scc_iterator() {}
|
||||
|
||||
public:
|
||||
typedef scc_iterator<GraphT, GT> _Self;
|
||||
static scc_iterator begin(const GraphT &G) {
|
||||
return scc_iterator(GT::getEntryNode(G));
|
||||
}
|
||||
static scc_iterator end(const GraphT &) { return scc_iterator(); }
|
||||
|
||||
// Provide static "constructors"...
|
||||
static inline _Self begin(const GraphT &G){return _Self(GT::getEntryNode(G));}
|
||||
static inline _Self end (const GraphT &) { return _Self(); }
|
||||
|
||||
// Direct loop termination test: I.isAtEnd() is more efficient than I == end()
|
||||
inline bool isAtEnd() const {
|
||||
/// \brief Direct loop termination test which is more efficient than
|
||||
/// comparison with \c end().
|
||||
bool isAtEnd() const {
|
||||
assert(!CurrentSCC.empty() || VisitStack.empty());
|
||||
return CurrentSCC.empty();
|
||||
}
|
||||
|
||||
inline bool operator==(const _Self& x) const {
|
||||
bool operator==(const scc_iterator &x) const {
|
||||
return VisitStack == x.VisitStack && CurrentSCC == x.CurrentSCC;
|
||||
}
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
|
||||
// Iterator traversal: forward iteration only
|
||||
inline _Self& operator++() { // Preincrement
|
||||
scc_iterator &operator++() {
|
||||
GetNextSCC();
|
||||
return *this;
|
||||
}
|
||||
inline _Self operator++(int) { // Postincrement
|
||||
_Self tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
|
||||
// Retrieve a reference to the current SCC
|
||||
inline const SccTy &operator*() const {
|
||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
||||
return CurrentSCC;
|
||||
}
|
||||
inline SccTy &operator*() {
|
||||
reference operator*() const {
|
||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
||||
return CurrentSCC;
|
||||
}
|
||||
|
||||
// hasLoop() -- Test if the current SCC has a loop. If it has more than one
|
||||
// node, this is trivially true. If not, it may still contain a loop if the
|
||||
// node has an edge back to itself.
|
||||
bool hasLoop() const {
|
||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
||||
if (CurrentSCC.size() > 1) return true;
|
||||
NodeType *N = CurrentSCC.front();
|
||||
for (ChildItTy CI = GT::child_begin(N), CE=GT::child_end(N); CI != CE; ++CI)
|
||||
if (*CI == N)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
/// \brief Test if the current SCC has a loop.
|
||||
///
|
||||
/// If the SCC has more than one node, this is trivially true. If not, it may
|
||||
/// still contain a loop if the node has an edge back to itself.
|
||||
bool hasLoop() const;
|
||||
|
||||
/// ReplaceNode - This informs the scc_iterator that the specified Old node
|
||||
/// has been deleted, and New is to be used in its place.
|
||||
/// This informs the \c scc_iterator that the specified \c Old node
|
||||
/// has been deleted, and \c New is to be used in its place.
|
||||
void ReplaceNode(NodeType *Old, NodeType *New) {
|
||||
assert(nodeVisitNumbers.count(Old) && "Old not in scc_iterator?");
|
||||
nodeVisitNumbers[New] = nodeVisitNumbers[Old];
|
||||
@ -193,25 +138,105 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class GraphT, class GT>
|
||||
void scc_iterator<GraphT, GT>::DFSVisitOne(NodeType *N) {
|
||||
++visitNum;
|
||||
nodeVisitNumbers[N] = visitNum;
|
||||
SCCNodeStack.push_back(N);
|
||||
VisitStack.push_back(StackElement(N, GT::child_begin(N), visitNum));
|
||||
#if 0 // Enable if needed when debugging.
|
||||
dbgs() << "TarjanSCC: Node " << N <<
|
||||
" : visitNum = " << visitNum << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Global constructor for the SCC iterator.
|
||||
template <class T>
|
||||
scc_iterator<T> scc_begin(const T &G) {
|
||||
template <class GraphT, class GT>
|
||||
void scc_iterator<GraphT, GT>::DFSVisitChildren() {
|
||||
assert(!VisitStack.empty());
|
||||
while (VisitStack.back().NextChild != GT::child_end(VisitStack.back().Node)) {
|
||||
// TOS has at least one more child so continue DFS
|
||||
NodeType *childN = *VisitStack.back().NextChild++;
|
||||
typename DenseMap<NodeType *, unsigned>::iterator Visited =
|
||||
nodeVisitNumbers.find(childN);
|
||||
if (Visited == nodeVisitNumbers.end()) {
|
||||
// this node has never been seen.
|
||||
DFSVisitOne(childN);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned childNum = Visited->second;
|
||||
if (VisitStack.back().MinVisited > childNum)
|
||||
VisitStack.back().MinVisited = childNum;
|
||||
}
|
||||
}
|
||||
|
||||
template <class GraphT, class GT> void scc_iterator<GraphT, GT>::GetNextSCC() {
|
||||
CurrentSCC.clear(); // Prepare to compute the next SCC
|
||||
while (!VisitStack.empty()) {
|
||||
DFSVisitChildren();
|
||||
|
||||
// Pop the leaf on top of the VisitStack.
|
||||
NodeType *visitingN = VisitStack.back().Node;
|
||||
unsigned minVisitNum = VisitStack.back().MinVisited;
|
||||
assert(VisitStack.back().NextChild == GT::child_end(visitingN));
|
||||
VisitStack.pop_back();
|
||||
|
||||
// Propagate MinVisitNum to parent so we can detect the SCC starting node.
|
||||
if (!VisitStack.empty() && VisitStack.back().MinVisited > minVisitNum)
|
||||
VisitStack.back().MinVisited = minVisitNum;
|
||||
|
||||
#if 0 // Enable if needed when debugging.
|
||||
dbgs() << "TarjanSCC: Popped node " << visitingN <<
|
||||
" : minVisitNum = " << minVisitNum << "; Node visit num = " <<
|
||||
nodeVisitNumbers[visitingN] << "\n";
|
||||
#endif
|
||||
|
||||
if (minVisitNum != nodeVisitNumbers[visitingN])
|
||||
continue;
|
||||
|
||||
// A full SCC is on the SCCNodeStack! It includes all nodes below
|
||||
// visitingN on the stack. Copy those nodes to CurrentSCC,
|
||||
// reset their minVisit values, and return (this suspends
|
||||
// the DFS traversal till the next ++).
|
||||
do {
|
||||
CurrentSCC.push_back(SCCNodeStack.back());
|
||||
SCCNodeStack.pop_back();
|
||||
nodeVisitNumbers[CurrentSCC.back()] = ~0U;
|
||||
} while (CurrentSCC.back() != visitingN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template <class GraphT, class GT>
|
||||
bool scc_iterator<GraphT, GT>::hasLoop() const {
|
||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
||||
if (CurrentSCC.size() > 1)
|
||||
return true;
|
||||
NodeType *N = CurrentSCC.front();
|
||||
for (ChildItTy CI = GT::child_begin(N), CE = GT::child_end(N); CI != CE;
|
||||
++CI)
|
||||
if (*CI == N)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Construct the begin iterator for a deduced graph type T.
|
||||
template <class T> scc_iterator<T> scc_begin(const T &G) {
|
||||
return scc_iterator<T>::begin(G);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
scc_iterator<T> scc_end(const T &G) {
|
||||
/// \brief Construct the end iterator for a deduced graph type T.
|
||||
template <class T> scc_iterator<T> scc_end(const T &G) {
|
||||
return scc_iterator<T>::end(G);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
scc_iterator<Inverse<T> > scc_begin(const Inverse<T> &G) {
|
||||
/// \brief Construct the begin iterator for a deduced graph type T's Inverse<T>.
|
||||
template <class T> scc_iterator<Inverse<T> > scc_begin(const Inverse<T> &G) {
|
||||
return scc_iterator<Inverse<T> >::begin(G);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
scc_iterator<Inverse<T> > scc_end(const Inverse<T> &G) {
|
||||
/// \brief Construct the end iterator for a deduced graph type T's Inverse<T>.
|
||||
template <class T> scc_iterator<Inverse<T> > scc_end(const Inverse<T> &G) {
|
||||
return scc_iterator<Inverse<T> >::end(G);
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,12 @@
|
||||
#ifndef LLVM_ADT_STLEXTRAS_H
|
||||
#define LLVM_ADT_STLEXTRAS_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cstddef> // for std::size_t
|
||||
#include <cstdlib> // for qsort
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
namespace llvm {
|
||||
@ -53,6 +55,131 @@ struct greater_ptr : public std::binary_function<Ty, Ty, bool> {
|
||||
}
|
||||
};
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
///
|
||||
/// This class does not own the callable, so it is not in general safe to store
|
||||
/// a function_ref.
|
||||
template<typename Fn> class function_ref;
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
template<typename Ret, typename ...Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(intptr_t callable, Params ...params);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Params ...params) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Params ...params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<typename Ret>
|
||||
class function_ref<Ret()> {
|
||||
Ret (*callback)(intptr_t callable);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable) {
|
||||
return (*reinterpret_cast<Callable*>(callable))();
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()() const { return callback(callable); }
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1>
|
||||
class function_ref<Ret(Param1)> {
|
||||
Ret (*callback)(intptr_t callable, Param1 param1);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Param1 param1) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Param1>(param1));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Param1 param1) {
|
||||
return callback(callable, std::forward<Param1>(param1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1, typename Param2>
|
||||
class function_ref<Ret(Param1, Param2)> {
|
||||
Ret (*callback)(intptr_t callable, Param1 param1, Param2 param2);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Param1 param1, Param2 param2) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Param1 param1, Param2 param2) {
|
||||
return callback(callable,
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1, typename Param2, typename Param3>
|
||||
class function_ref<Ret(Param1, Param2, Param3)> {
|
||||
Ret (*callback)(intptr_t callable, Param1 param1, Param2 param2, Param3 param3);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Param1 param1, Param2 param2,
|
||||
Param3 param3) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2),
|
||||
std::forward<Param3>(param3));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Param1 param1, Param2 param2, Param3 param3) {
|
||||
return callback(callable,
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2),
|
||||
std::forward<Param3>(param3));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// deleter - Very very very simple method that is used to invoke operator
|
||||
// delete on something. It is used like this:
|
||||
//
|
||||
@ -95,8 +222,6 @@ public:
|
||||
|
||||
inline explicit mapped_iterator(const RootIt &I, UnaryFunc F)
|
||||
: current(I), Fn(F) {}
|
||||
inline mapped_iterator(const mapped_iterator &It)
|
||||
: current(It.current), Fn(It.Fn) {}
|
||||
|
||||
inline value_type operator*() const { // All this work to do this
|
||||
return Fn(*current); // little change
|
||||
@ -141,82 +266,10 @@ inline mapped_iterator<ItTy, FuncTy> map_iterator(const ItTy &I, FuncTy F) {
|
||||
return mapped_iterator<ItTy, FuncTy>(I, F);
|
||||
}
|
||||
|
||||
|
||||
// next/prior - These functions unlike std::advance do not modify the
|
||||
// passed iterator but return a copy.
|
||||
//
|
||||
// next(myIt) returns copy of myIt incremented once
|
||||
// next(myIt, n) returns copy of myIt incremented n times
|
||||
// prior(myIt) returns copy of myIt decremented once
|
||||
// prior(myIt, n) returns copy of myIt decremented n times
|
||||
|
||||
template <typename ItTy, typename Dist>
|
||||
inline ItTy next(ItTy it, Dist n)
|
||||
{
|
||||
std::advance(it, n);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename ItTy>
|
||||
inline ItTy next(ItTy it)
|
||||
{
|
||||
return ++it;
|
||||
}
|
||||
|
||||
template <typename ItTy, typename Dist>
|
||||
inline ItTy prior(ItTy it, Dist n)
|
||||
{
|
||||
std::advance(it, -n);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename ItTy>
|
||||
inline ItTy prior(ItTy it)
|
||||
{
|
||||
return --it;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <utility>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// tie - this function ties two objects and returns a temporary object
|
||||
// that is assignable from a std::pair. This can be used to make code
|
||||
// more readable when using values returned from functions bundled in
|
||||
// a std::pair. Since an example is worth 1000 words:
|
||||
//
|
||||
// typedef std::map<int, int> Int2IntMap;
|
||||
//
|
||||
// Int2IntMap myMap;
|
||||
// Int2IntMap::iterator where;
|
||||
// bool inserted;
|
||||
// tie(where, inserted) = myMap.insert(std::make_pair(123,456));
|
||||
//
|
||||
// if (inserted)
|
||||
// // do stuff
|
||||
// else
|
||||
// // do other stuff
|
||||
template <typename T1, typename T2>
|
||||
struct tier {
|
||||
typedef T1 &first_type;
|
||||
typedef T2 &second_type;
|
||||
|
||||
first_type first;
|
||||
second_type second;
|
||||
|
||||
tier(first_type f, second_type s) : first(f), second(s) { }
|
||||
tier& operator=(const std::pair<T1, T2>& p) {
|
||||
first = p.first;
|
||||
second = p.second;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline tier<T1, T2> tie(T1& f, T2& s) {
|
||||
return tier<T1, T2>(f, s);
|
||||
}
|
||||
|
||||
/// \brief Function object to check whether the first component of a std::pair
|
||||
/// compares less than the first component of another std::pair.
|
||||
struct less_first {
|
||||
@ -237,27 +290,20 @@ struct less_second {
|
||||
// Extra additions for arrays
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Find where an array ends (for ending iterators)
|
||||
/// This returns a pointer to the byte immediately
|
||||
/// after the end of an array.
|
||||
template<class T, std::size_t N>
|
||||
inline T *array_endof(T (&x)[N]) {
|
||||
return x+N;
|
||||
}
|
||||
|
||||
/// Find the length of an array.
|
||||
template<class T, std::size_t N>
|
||||
inline size_t array_lengthof(T (&)[N]) {
|
||||
template <class T, std::size_t N>
|
||||
LLVM_CONSTEXPR inline size_t array_lengthof(T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
|
||||
/// array_pod_sort_comparator - This is helper function for array_pod_sort,
|
||||
/// which just uses operator< on T.
|
||||
/// Adapt std::less<T> for array_pod_sort.
|
||||
template<typename T>
|
||||
inline int array_pod_sort_comparator(const void *P1, const void *P2) {
|
||||
if (*reinterpret_cast<const T*>(P1) < *reinterpret_cast<const T*>(P2))
|
||||
if (std::less<T>()(*reinterpret_cast<const T*>(P1),
|
||||
*reinterpret_cast<const T*>(P2)))
|
||||
return -1;
|
||||
if (*reinterpret_cast<const T*>(P2) < *reinterpret_cast<const T*>(P1))
|
||||
if (std::less<T>()(*reinterpret_cast<const T*>(P2),
|
||||
*reinterpret_cast<const T*>(P1)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -280,7 +326,7 @@ inline int (*get_array_pod_sort_comparator(const T &))
|
||||
/// possible.
|
||||
///
|
||||
/// This function assumes that you have simple POD-like types that can be
|
||||
/// compared with operator< and can be moved with memcpy. If this isn't true,
|
||||
/// compared with std::less and can be moved with memcpy. If this isn't true,
|
||||
/// you should use std::sort.
|
||||
///
|
||||
/// NOTE: If qsort_r were portable, we could allow a custom comparator and
|
||||
@ -327,6 +373,170 @@ void DeleteContainerSeconds(Container &C) {
|
||||
C.clear();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <memory>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
// Implement make_unique according to N3656.
|
||||
|
||||
/// \brief Constructs a `new T()` with the given args and returns a
|
||||
/// `unique_ptr<T>` which owns the object.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// auto p = make_unique<int>();
|
||||
/// auto p = make_unique<std::tuple<int, int>>(0, 1);
|
||||
template <class T, class... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Args &&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/// \brief Constructs a `new T[n]` with the given args and returns a
|
||||
/// `unique_ptr<T[]>` which owns the object.
|
||||
///
|
||||
/// \param n size of the new array.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// auto p = make_unique<int[]>(2); // value-initializes the array with 0's.
|
||||
template <class T>
|
||||
typename std::enable_if<std::is_array<T>::value && std::extent<T>::value == 0,
|
||||
std::unique_ptr<T>>::type
|
||||
make_unique(size_t n) {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]());
|
||||
}
|
||||
|
||||
/// This function isn't used and is only here to provide better compile errors.
|
||||
template <class T, class... Args>
|
||||
typename std::enable_if<std::extent<T>::value != 0>::type
|
||||
make_unique(Args &&...) LLVM_DELETED_FUNCTION;
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique() {
|
||||
return std::unique_ptr<T>(new T());
|
||||
}
|
||||
|
||||
template <class T, class Arg1>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1),
|
||||
std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7, class Arg8>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7), std::forward<Arg8>(arg8)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7, class Arg8, class Arg9>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8, Arg9 &&arg9) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7), std::forward<Arg8>(arg8),
|
||||
std::forward<Arg9>(arg9)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7, class Arg8, class Arg9, class Arg10>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8, Arg9 &&arg9, Arg10 &&arg10) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7), std::forward<Arg8>(arg8),
|
||||
std::forward<Arg9>(arg9), std::forward<Arg10>(arg10)));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<std::is_array<T>::value &&std::extent<T>::value == 0,
|
||||
std::unique_ptr<T>>::type
|
||||
make_unique(size_t n) {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename First, typename Second>
|
||||
struct pair_hash {
|
||||
size_t operator()(const std::pair<First, Second> &P) const {
|
||||
return std::hash<First>()(P.first) * 31 + std::hash<Second>()(P.second);
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -148,6 +148,7 @@ public:
|
||||
/// ScopeTy - This is a helpful typedef that allows clients to get easy access
|
||||
/// to the name of the scope for this hash table.
|
||||
typedef ScopedHashTableScope<K, V, KInfo, AllocatorTy> ScopeTy;
|
||||
typedef unsigned size_type;
|
||||
private:
|
||||
typedef ScopedHashTableVal<K, V> ValTy;
|
||||
DenseMap<K, ValTy*, KInfo> TopLevelMap;
|
||||
@ -159,20 +160,19 @@ private:
|
||||
void operator=(const ScopedHashTable&); // NOT YET IMPLEMENTED
|
||||
friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
|
||||
public:
|
||||
ScopedHashTable() : CurScope(0) {}
|
||||
ScopedHashTable() : CurScope(nullptr) {}
|
||||
ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {}
|
||||
~ScopedHashTable() {
|
||||
assert(CurScope == 0 && TopLevelMap.empty() && "Scope imbalance!");
|
||||
assert(!CurScope && TopLevelMap.empty() && "Scope imbalance!");
|
||||
}
|
||||
|
||||
|
||||
/// Access to the allocator.
|
||||
typedef typename ReferenceAdder<AllocatorTy>::result AllocatorRefTy;
|
||||
typedef typename ReferenceAdder<const AllocatorTy>::result AllocatorCRefTy;
|
||||
AllocatorRefTy getAllocator() { return Allocator; }
|
||||
AllocatorCRefTy getAllocator() const { return Allocator; }
|
||||
AllocatorTy &getAllocator() { return Allocator; }
|
||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||
|
||||
bool count(const K &Key) const {
|
||||
/// Return 1 if the specified key is in the table, 0 otherwise.
|
||||
size_type count(const K &Key) const {
|
||||
return TopLevelMap.count(Key);
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ ScopedHashTableScope<K, V, KInfo, Allocator>::
|
||||
ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) {
|
||||
PrevScope = HT.CurScope;
|
||||
HT.CurScope = this;
|
||||
LastValInScope = 0;
|
||||
LastValInScope = nullptr;
|
||||
}
|
||||
|
||||
template <typename K, typename V, typename KInfo, typename Allocator>
|
||||
@ -233,7 +233,7 @@ ScopedHashTableScope<K, V, KInfo, Allocator>::~ScopedHashTableScope() {
|
||||
// Pop and delete all values corresponding to this scope.
|
||||
while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) {
|
||||
// Pop this value out of the TopLevelMap.
|
||||
if (ThisEntry->getNextForKey() == 0) {
|
||||
if (!ThisEntry->getNextForKey()) {
|
||||
assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry &&
|
||||
"Scope imbalance!");
|
||||
HT.TopLevelMap.erase(ThisEntry->getKey());
|
||||
|
@ -195,11 +195,10 @@ private:
|
||||
set_type &set_;
|
||||
|
||||
public:
|
||||
typedef typename UnaryPredicate::argument_type argument_type;
|
||||
|
||||
TestAndEraseFromSet(UnaryPredicate P, set_type &set_) : P(P), set_(set_) {}
|
||||
|
||||
bool operator()(argument_type Arg) {
|
||||
template <typename ArgumentT>
|
||||
bool operator()(const ArgumentT &Arg) {
|
||||
if (P(Arg)) {
|
||||
set_.erase(Arg);
|
||||
return true;
|
||||
|
@ -54,6 +54,7 @@ class SmallBitVector {
|
||||
};
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
// Encapsulation of a single bit.
|
||||
class reference {
|
||||
SmallBitVector &TheVector;
|
||||
@ -153,11 +154,9 @@ public:
|
||||
switchToLarge(new BitVector(*RHS.getPointer()));
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
SmallBitVector(SmallBitVector &&RHS) : X(RHS.X) {
|
||||
RHS.X = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
~SmallBitVector() {
|
||||
if (!isSmall())
|
||||
@ -175,7 +174,7 @@ public:
|
||||
}
|
||||
|
||||
/// count - Returns the number of bits which are set.
|
||||
unsigned count() const {
|
||||
size_type count() const {
|
||||
if (isSmall()) {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
if (NumBaseBits == 32)
|
||||
@ -506,7 +505,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
const SmallBitVector &operator=(SmallBitVector &&RHS) {
|
||||
if (this != &RHS) {
|
||||
clear();
|
||||
@ -514,7 +512,6 @@ public:
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(SmallBitVector &RHS) {
|
||||
std::swap(X, RHS.X);
|
||||
|
@ -8,7 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallPtrSet class. See the doxygen comment for
|
||||
// SmallPtrSetImpl for more details on the algorithm used.
|
||||
// SmallPtrSetImplBase for more details on the algorithm used.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -27,7 +27,7 @@ namespace llvm {
|
||||
|
||||
class SmallPtrSetIteratorImpl;
|
||||
|
||||
/// SmallPtrSetImpl - This is the common code shared among all the
|
||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||
/// for small and one for large sets.
|
||||
///
|
||||
@ -45,7 +45,7 @@ class SmallPtrSetIteratorImpl;
|
||||
/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
|
||||
/// more. When this happens, the table is doubled in size.
|
||||
///
|
||||
class SmallPtrSetImpl {
|
||||
class SmallPtrSetImplBase {
|
||||
friend class SmallPtrSetIteratorImpl;
|
||||
protected:
|
||||
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
||||
@ -60,19 +60,22 @@ protected:
|
||||
unsigned NumElements;
|
||||
unsigned NumTombstones;
|
||||
|
||||
// Helper to copy construct a SmallPtrSet.
|
||||
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl& that);
|
||||
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize) :
|
||||
// Helpers to copy and move construct a SmallPtrSet.
|
||||
SmallPtrSetImplBase(const void **SmallStorage, const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that);
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) :
|
||||
SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) {
|
||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||
"Initial size must be a power of two!");
|
||||
clear();
|
||||
}
|
||||
~SmallPtrSetImpl();
|
||||
~SmallPtrSetImplBase();
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
|
||||
unsigned size() const { return NumElements; }
|
||||
size_type size() const { return NumElements; }
|
||||
|
||||
void clear() {
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
@ -128,13 +131,14 @@ private:
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
void Grow(unsigned NewSize);
|
||||
|
||||
void operator=(const SmallPtrSetImpl &RHS) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const SmallPtrSetImplBase &RHS) LLVM_DELETED_FUNCTION;
|
||||
protected:
|
||||
/// swap - Swaps the elements of two sets.
|
||||
/// Note: This method assumes that both sets have the same small size.
|
||||
void swap(SmallPtrSetImpl &RHS);
|
||||
void swap(SmallPtrSetImplBase &RHS);
|
||||
|
||||
void CopyFrom(const SmallPtrSetImpl &RHS);
|
||||
void CopyFrom(const SmallPtrSetImplBase &RHS);
|
||||
void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
};
|
||||
|
||||
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||
@ -163,8 +167,8 @@ protected:
|
||||
void AdvanceIfNotValid() {
|
||||
assert(Bucket <= End);
|
||||
while (Bucket != End &&
|
||||
(*Bucket == SmallPtrSetImpl::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImpl::getTombstoneMarker()))
|
||||
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||
++Bucket;
|
||||
}
|
||||
};
|
||||
@ -228,26 +232,25 @@ struct RoundUpToPowerOfTwo {
|
||||
};
|
||||
|
||||
|
||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||
/// power of two if it is not already a power of two. See the comments above
|
||||
/// SmallPtrSetImpl for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl {
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
||||
const void *SmallStorage[SmallSizePowTwo];
|
||||
/// \brief A templated base class for \c SmallPtrSet which provides the
|
||||
/// typesafe interface that is common across all small sizes.
|
||||
///
|
||||
/// This is particularly useful for passing around between interface boundaries
|
||||
/// to avoid encoding a particular small size in the interface boundary.
|
||||
template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
||||
protected:
|
||||
// Constructors that forward to the base.
|
||||
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
|
||||
: SmallPtrSetImplBase(SmallStorage, that) {}
|
||||
SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImpl &&that)
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
|
||||
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
|
||||
|
||||
public:
|
||||
SmallPtrSet() : SmallPtrSetImpl(SmallStorage, SmallSizePowTwo) {}
|
||||
SmallPtrSet(const SmallPtrSet &that) : SmallPtrSetImpl(SmallStorage, that) {}
|
||||
|
||||
template<typename It>
|
||||
SmallPtrSet(It I, It E) : SmallPtrSetImpl(SmallStorage, SmallSizePowTwo) {
|
||||
insert(I, E);
|
||||
}
|
||||
|
||||
/// insert - This returns true if the pointer was new to the set, false if it
|
||||
/// was already in the set.
|
||||
bool insert(PtrType Ptr) {
|
||||
@ -260,9 +263,9 @@ public:
|
||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
}
|
||||
|
||||
/// count - Return true if the specified pointer is in the set.
|
||||
bool count(PtrType Ptr) const {
|
||||
return count_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||
size_type count(PtrType Ptr) const {
|
||||
return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0;
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
@ -279,18 +282,48 @@ public:
|
||||
inline iterator end() const {
|
||||
return iterator(CurArray+CurArraySize, CurArray+CurArraySize);
|
||||
}
|
||||
};
|
||||
|
||||
// Allow assignment from any smallptrset with the same element type even if it
|
||||
// doesn't have the same smallsize.
|
||||
const SmallPtrSet<PtrType, SmallSize>&
|
||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||
/// power of two if it is not already a power of two. See the comments above
|
||||
/// SmallPtrSetImplBase for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
typedef SmallPtrSetImpl<PtrType> BaseT;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
||||
const void *SmallStorage[SmallSizePowTwo];
|
||||
public:
|
||||
SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
|
||||
SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
|
||||
SmallPtrSet(SmallPtrSet &&that)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
|
||||
|
||||
template<typename It>
|
||||
SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
CopyFrom(RHS);
|
||||
if (&RHS != this)
|
||||
this->CopyFrom(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize>&
|
||||
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
|
||||
if (&RHS != this)
|
||||
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap - Swaps the elements of two sets.
|
||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
SmallPtrSetImpl::swap(RHS);
|
||||
SmallPtrSetImplBase::swap(RHS);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -37,18 +37,22 @@ class SmallSet {
|
||||
typedef typename SmallVector<T, N>::const_iterator VIterator;
|
||||
typedef typename SmallVector<T, N>::iterator mutable_iterator;
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
SmallSet() {}
|
||||
|
||||
bool empty() const { return Vector.empty() && Set.empty(); }
|
||||
unsigned size() const {
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||
return Vector.empty() && Set.empty();
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return isSmall() ? Vector.size() : Set.size();
|
||||
}
|
||||
|
||||
/// count - Return true if the element is in the set.
|
||||
bool count(const T &V) const {
|
||||
/// count - Return 1 if the element is in the set, 0 otherwise.
|
||||
size_type count(const T &V) const {
|
||||
if (isSmall()) {
|
||||
// Since the collection is small, just do a linear search.
|
||||
return vfind(V) != Vector.end();
|
||||
return vfind(V) == Vector.end() ? 0 : 1;
|
||||
} else {
|
||||
return Set.count(V);
|
||||
}
|
||||
|
@ -34,9 +34,6 @@ public:
|
||||
template<typename ItTy>
|
||||
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
|
||||
|
||||
/// Copy ctor.
|
||||
SmallString(const SmallString &RHS) : SmallVector<char, InternalLen>(RHS) {}
|
||||
|
||||
// Note that in order to add new overloads for append & assign, we have to
|
||||
// duplicate the inherited versions so as not to inadvertently hide them.
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#ifndef LLVM_ADT_SMALLVECTOR_H
|
||||
#define LLVM_ADT_SMALLVECTOR_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
@ -183,13 +184,9 @@ protected:
|
||||
/// std::move, but not all stdlibs actually provide that.
|
||||
template<typename It1, typename It2>
|
||||
static It2 move(It1 I, It1 E, It2 Dest) {
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
for (; I != E; ++I, ++Dest)
|
||||
*Dest = ::std::move(*I);
|
||||
return Dest;
|
||||
#else
|
||||
return ::std::copy(I, E, Dest);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// move_backward - Use move-assignment to move the range
|
||||
@ -198,25 +195,17 @@ protected:
|
||||
/// std::move_backward, but not all stdlibs actually provide that.
|
||||
template<typename It1, typename It2>
|
||||
static It2 move_backward(It1 I, It1 E, It2 Dest) {
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
while (I != E)
|
||||
*--Dest = ::std::move(*--E);
|
||||
return Dest;
|
||||
#else
|
||||
return ::std::copy_backward(I, E, Dest);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// uninitialized_move - Move the range [I, E) into the uninitialized
|
||||
/// memory starting with "Dest", constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
for (; I != E; ++I, ++Dest)
|
||||
::new ((void*) &*Dest) T(::std::move(*I));
|
||||
#else
|
||||
::std::uninitialized_copy(I, E, Dest);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// uninitialized_copy - Copy the range [I, E) onto the uninitialized
|
||||
@ -231,32 +220,22 @@ protected:
|
||||
/// Guarantees space for at least one more element, or MinSize more
|
||||
/// elements if specified.
|
||||
void grow(size_t MinSize = 0);
|
||||
|
||||
|
||||
public:
|
||||
void push_back(const T &Elt) {
|
||||
if (this->EndX < this->CapacityX) {
|
||||
Retry:
|
||||
::new ((void*) this->end()) T(Elt);
|
||||
this->setEnd(this->end()+1);
|
||||
return;
|
||||
}
|
||||
this->grow();
|
||||
goto Retry;
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void*) this->end()) T(Elt);
|
||||
this->setEnd(this->end()+1);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
void push_back(T &&Elt) {
|
||||
if (this->EndX < this->CapacityX) {
|
||||
Retry:
|
||||
::new ((void*) this->end()) T(::std::move(Elt));
|
||||
this->setEnd(this->end()+1);
|
||||
return;
|
||||
}
|
||||
this->grow();
|
||||
goto Retry;
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void*) this->end()) T(::std::move(Elt));
|
||||
this->setEnd(this->end()+1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void pop_back() {
|
||||
this->setEnd(this->end()-1);
|
||||
this->end()->~T();
|
||||
@ -268,7 +247,7 @@ template <typename T, bool isPodLike>
|
||||
void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
|
||||
size_t CurCapacity = this->capacity();
|
||||
size_t CurSize = this->size();
|
||||
// Always grow, even from zero.
|
||||
// Always grow, even from zero.
|
||||
size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
|
||||
if (NewCapacity < MinSize)
|
||||
NewCapacity = MinSize;
|
||||
@ -348,16 +327,12 @@ protected:
|
||||
}
|
||||
public:
|
||||
void push_back(const T &Elt) {
|
||||
if (this->EndX < this->CapacityX) {
|
||||
Retry:
|
||||
memcpy(this->end(), &Elt, sizeof(T));
|
||||
this->setEnd(this->end()+1);
|
||||
return;
|
||||
}
|
||||
this->grow();
|
||||
goto Retry;
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
memcpy(this->end(), &Elt, sizeof(T));
|
||||
this->setEnd(this->end()+1);
|
||||
}
|
||||
|
||||
|
||||
void pop_back() {
|
||||
this->setEnd(this->end()-1);
|
||||
}
|
||||
@ -405,7 +380,8 @@ public:
|
||||
} else if (N > this->size()) {
|
||||
if (this->capacity() < N)
|
||||
this->grow(N);
|
||||
std::uninitialized_fill(this->end(), this->begin()+N, T());
|
||||
for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
|
||||
new (&*I) T();
|
||||
this->setEnd(this->begin()+N);
|
||||
}
|
||||
}
|
||||
@ -428,11 +404,7 @@ public:
|
||||
}
|
||||
|
||||
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
T Result = ::std::move(this->back());
|
||||
#else
|
||||
T Result = this->back();
|
||||
#endif
|
||||
this->pop_back();
|
||||
return Result;
|
||||
}
|
||||
@ -501,7 +473,6 @@ public:
|
||||
return(N);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
iterator insert(iterator I, T &&Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
this->push_back(::std::move(Elt));
|
||||
@ -511,28 +482,26 @@ public:
|
||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
|
||||
if (this->EndX < this->CapacityX) {
|
||||
Retry:
|
||||
::new ((void*) this->end()) T(::std::move(this->back()));
|
||||
this->setEnd(this->end()+1);
|
||||
// Push everything else over.
|
||||
this->move_backward(I, this->end()-1, this->end());
|
||||
|
||||
// If we just moved the element we're inserting, be sure to update
|
||||
// the reference.
|
||||
T *EltPtr = &Elt;
|
||||
if (I <= EltPtr && EltPtr < this->EndX)
|
||||
++EltPtr;
|
||||
|
||||
*I = ::std::move(*EltPtr);
|
||||
return I;
|
||||
if (this->EndX >= this->CapacityX) {
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow();
|
||||
I = this->begin()+EltNo;
|
||||
}
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow();
|
||||
I = this->begin()+EltNo;
|
||||
goto Retry;
|
||||
|
||||
::new ((void*) this->end()) T(::std::move(this->back()));
|
||||
// Push everything else over.
|
||||
this->move_backward(I, this->end()-1, this->end());
|
||||
this->setEnd(this->end()+1);
|
||||
|
||||
// If we just moved the element we're inserting, be sure to update
|
||||
// the reference.
|
||||
T *EltPtr = &Elt;
|
||||
if (I <= EltPtr && EltPtr < this->EndX)
|
||||
++EltPtr;
|
||||
|
||||
*I = ::std::move(*EltPtr);
|
||||
return I;
|
||||
}
|
||||
#endif
|
||||
|
||||
iterator insert(iterator I, const T &Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
@ -543,26 +512,24 @@ public:
|
||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
|
||||
if (this->EndX < this->CapacityX) {
|
||||
Retry:
|
||||
::new ((void*) this->end()) T(this->back());
|
||||
this->setEnd(this->end()+1);
|
||||
// Push everything else over.
|
||||
this->move_backward(I, this->end()-1, this->end());
|
||||
|
||||
// If we just moved the element we're inserting, be sure to update
|
||||
// the reference.
|
||||
const T *EltPtr = &Elt;
|
||||
if (I <= EltPtr && EltPtr < this->EndX)
|
||||
++EltPtr;
|
||||
|
||||
*I = *EltPtr;
|
||||
return I;
|
||||
if (this->EndX >= this->CapacityX) {
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow();
|
||||
I = this->begin()+EltNo;
|
||||
}
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow();
|
||||
I = this->begin()+EltNo;
|
||||
goto Retry;
|
||||
::new ((void*) this->end()) T(std::move(this->back()));
|
||||
// Push everything else over.
|
||||
this->move_backward(I, this->end()-1, this->end());
|
||||
this->setEnd(this->end()+1);
|
||||
|
||||
// If we just moved the element we're inserting, be sure to update
|
||||
// the reference.
|
||||
const T *EltPtr = &Elt;
|
||||
if (I <= EltPtr && EltPtr < this->EndX)
|
||||
++EltPtr;
|
||||
|
||||
*I = *EltPtr;
|
||||
return I;
|
||||
}
|
||||
|
||||
iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
|
||||
@ -589,7 +556,8 @@ public:
|
||||
// reallocate the vector.
|
||||
if (size_t(this->end()-I) >= NumToInsert) {
|
||||
T *OldEnd = this->end();
|
||||
append(this->end()-NumToInsert, this->end());
|
||||
append(std::move_iterator<iterator>(this->end() - NumToInsert),
|
||||
std::move_iterator<iterator>(this->end()));
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
@ -642,7 +610,8 @@ public:
|
||||
// reallocate the vector.
|
||||
if (size_t(this->end()-I) >= NumToInsert) {
|
||||
T *OldEnd = this->end();
|
||||
append(this->end()-NumToInsert, this->end());
|
||||
append(std::move_iterator<iterator>(this->end() - NumToInsert),
|
||||
std::move_iterator<iterator>(this->end()));
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
@ -673,9 +642,7 @@ public:
|
||||
|
||||
SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
|
||||
#endif
|
||||
|
||||
bool operator==(const SmallVectorImpl &RHS) const {
|
||||
if (this->size() != RHS.size()) return false;
|
||||
@ -793,7 +760,6 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||
// Avoid self-assignment.
|
||||
@ -842,7 +808,7 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||
this->grow(RHSSize);
|
||||
} else if (CurSize) {
|
||||
// Otherwise, use assignment for the already-constructed elements.
|
||||
this->move(RHS.begin(), RHS.end(), this->begin());
|
||||
this->move(RHS.begin(), RHS.begin()+CurSize, this->begin());
|
||||
}
|
||||
|
||||
// Move-construct the new elements in place.
|
||||
@ -855,7 +821,6 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||
RHS.clear();
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Storage for the SmallVector elements which aren't contained in
|
||||
/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1'
|
||||
@ -894,6 +859,12 @@ public:
|
||||
this->append(S, E);
|
||||
}
|
||||
|
||||
template <typename RangeTy>
|
||||
explicit SmallVector(const llvm::iterator_range<RangeTy> R)
|
||||
: SmallVectorImpl<T>(N) {
|
||||
this->append(R.begin(), R.end());
|
||||
}
|
||||
|
||||
SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(RHS);
|
||||
@ -904,7 +875,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
@ -914,8 +884,6 @@ public:
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
template<typename T, unsigned N>
|
||||
|
@ -45,6 +45,7 @@ struct SparseBitVectorElement
|
||||
: public ilist_node<SparseBitVectorElement<ElementSize> > {
|
||||
public:
|
||||
typedef unsigned long BitWord;
|
||||
typedef unsigned size_type;
|
||||
enum {
|
||||
BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT,
|
||||
BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE,
|
||||
@ -120,7 +121,7 @@ public:
|
||||
return Bits[Idx / BITWORD_SIZE] & (1L << (Idx % BITWORD_SIZE));
|
||||
}
|
||||
|
||||
unsigned count() const {
|
||||
size_type count() const {
|
||||
unsigned NumBits = 0;
|
||||
for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i)
|
||||
if (sizeof(BitWord) == 4)
|
||||
@ -382,7 +383,7 @@ class SparseBitVector {
|
||||
AtEnd = true;
|
||||
return;
|
||||
}
|
||||
// Set up for next non zero word in bitmap.
|
||||
// Set up for next non-zero word in bitmap.
|
||||
BitNumber = Iter->index() * ElementSize;
|
||||
NextSetBitNumber = Iter->find_first();
|
||||
BitNumber += NextSetBitNumber;
|
||||
|
@ -76,6 +76,10 @@ template<typename ValueT,
|
||||
typename KeyFunctorT = llvm::identity<unsigned>,
|
||||
typename SparseT = uint8_t>
|
||||
class SparseMultiSet {
|
||||
static_assert(std::numeric_limits<SparseT>::is_integer &&
|
||||
!std::numeric_limits<SparseT>::is_signed,
|
||||
"SparseT must be an unsigned integer type");
|
||||
|
||||
/// The actual data that's stored, as a doubly-linked list implemented via
|
||||
/// indices into the DenseVector. The doubly linked list is implemented
|
||||
/// circular in Prev indices, and INVALID-terminated in Next indices. This
|
||||
@ -181,9 +185,10 @@ public:
|
||||
typedef const ValueT &const_reference;
|
||||
typedef ValueT *pointer;
|
||||
typedef const ValueT *const_pointer;
|
||||
typedef unsigned size_type;
|
||||
|
||||
SparseMultiSet()
|
||||
: Sparse(0), Universe(0), FreelistIdx(SMSNode::INVALID), NumFree(0) { }
|
||||
: Sparse(nullptr), Universe(0), FreelistIdx(SMSNode::INVALID), NumFree(0) {}
|
||||
|
||||
~SparseMultiSet() { free(Sparse); }
|
||||
|
||||
@ -245,16 +250,6 @@ public:
|
||||
typedef typename super::pointer pointer;
|
||||
typedef typename super::reference reference;
|
||||
|
||||
iterator_base(const iterator_base &RHS)
|
||||
: SMS(RHS.SMS), Idx(RHS.Idx), SparseIdx(RHS.SparseIdx) { }
|
||||
|
||||
const iterator_base &operator=(const iterator_base &RHS) {
|
||||
SMS = RHS.SMS;
|
||||
Idx = RHS.Idx;
|
||||
SparseIdx = RHS.SparseIdx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
assert(isKeyed() && SMS->sparseIndex(SMS->Dense[Idx].Data) == SparseIdx &&
|
||||
"Dereferencing iterator of invalid key or index");
|
||||
@ -333,7 +328,7 @@ public:
|
||||
/// This is not the same as BitVector::size() which returns the size of the
|
||||
/// universe.
|
||||
///
|
||||
unsigned size() const {
|
||||
size_type size() const {
|
||||
assert(NumFree <= Dense.size() && "Out-of-bounds free entries");
|
||||
return Dense.size() - NumFree;
|
||||
}
|
||||
@ -354,9 +349,6 @@ public:
|
||||
///
|
||||
iterator findIndex(unsigned Idx) {
|
||||
assert(Idx < Universe && "Key out of range");
|
||||
assert(std::numeric_limits<SparseT>::is_integer &&
|
||||
!std::numeric_limits<SparseT>::is_signed &&
|
||||
"SparseT must be an unsigned integer type");
|
||||
const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
|
||||
for (unsigned i = Sparse[Idx], e = Dense.size(); i < e; i += Stride) {
|
||||
const unsigned FoundIdx = sparseIndex(Dense[i]);
|
||||
@ -387,7 +379,7 @@ public:
|
||||
|
||||
/// Returns the number of elements identified by Key. This will be linear in
|
||||
/// the number of elements of that key.
|
||||
unsigned count(const KeyT &Key) const {
|
||||
size_type count(const KeyT &Key) const {
|
||||
unsigned Ret = 0;
|
||||
for (const_iterator It = find(Key); It != end(); ++It)
|
||||
++Ret;
|
||||
|
@ -118,8 +118,13 @@ template<typename ValueT,
|
||||
typename KeyFunctorT = llvm::identity<unsigned>,
|
||||
typename SparseT = uint8_t>
|
||||
class SparseSet {
|
||||
static_assert(std::numeric_limits<SparseT>::is_integer &&
|
||||
!std::numeric_limits<SparseT>::is_signed,
|
||||
"SparseT must be an unsigned integer type");
|
||||
|
||||
typedef typename KeyFunctorT::argument_type KeyT;
|
||||
typedef SmallVector<ValueT, 8> DenseT;
|
||||
typedef unsigned size_type;
|
||||
DenseT Dense;
|
||||
SparseT *Sparse;
|
||||
unsigned Universe;
|
||||
@ -138,7 +143,7 @@ public:
|
||||
typedef ValueT *pointer;
|
||||
typedef const ValueT *const_pointer;
|
||||
|
||||
SparseSet() : Sparse(0), Universe(0) {}
|
||||
SparseSet() : Sparse(nullptr), Universe(0) {}
|
||||
~SparseSet() { free(Sparse); }
|
||||
|
||||
/// setUniverse - Set the universe size which determines the largest key the
|
||||
@ -182,7 +187,7 @@ public:
|
||||
/// This is not the same as BitVector::size() which returns the size of the
|
||||
/// universe.
|
||||
///
|
||||
unsigned size() const { return Dense.size(); }
|
||||
size_type size() const { return Dense.size(); }
|
||||
|
||||
/// clear - Clears the set. This is a very fast constant time operation.
|
||||
///
|
||||
@ -198,9 +203,6 @@ public:
|
||||
///
|
||||
iterator findIndex(unsigned Idx) {
|
||||
assert(Idx < Universe && "Key out of range");
|
||||
assert(std::numeric_limits<SparseT>::is_integer &&
|
||||
!std::numeric_limits<SparseT>::is_signed &&
|
||||
"SparseT must be an unsigned integer type");
|
||||
const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
|
||||
for (unsigned i = Sparse[Idx], e = size(); i < e; i += Stride) {
|
||||
const unsigned FoundIdx = ValIndexOf(Dense[i]);
|
||||
@ -227,10 +229,11 @@ public:
|
||||
return const_cast<SparseSet*>(this)->findIndex(KeyIndexOf(Key));
|
||||
}
|
||||
|
||||
/// count - Returns true if this set contains an element identified by Key.
|
||||
/// count - Returns 1 if this set contains an element identified by Key,
|
||||
/// 0 otherwise.
|
||||
///
|
||||
bool count(const KeyT &Key) const {
|
||||
return find(Key) != end();
|
||||
size_type count(const KeyT &Key) const {
|
||||
return find(Key) == end() ? 0 : 1;
|
||||
}
|
||||
|
||||
/// insert - Attempts to insert a new element.
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
/// construct - This should only be called for non-global statistics.
|
||||
void construct(const char *name, const char *desc) {
|
||||
Name = name; Desc = desc;
|
||||
Value = 0; Initialized = 0;
|
||||
Value = 0; Initialized = false;
|
||||
}
|
||||
|
||||
// Allow use of this class as the value itself.
|
||||
|
@ -14,9 +14,9 @@
|
||||
#ifndef LLVM_ADT_STRINGEXTRAS_H
|
||||
#define LLVM_ADT_STRINGEXTRAS_H
|
||||
|
||||
#include <iterator>
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <iterator>
|
||||
|
||||
namespace llvm {
|
||||
template<typename T> class SmallVectorImpl;
|
||||
@ -28,6 +28,11 @@ static inline char hexdigit(unsigned X, bool LowerCase = false) {
|
||||
return X < 10 ? '0' + X : HexChar + X - 10;
|
||||
}
|
||||
|
||||
/// Construct a string ref from a boolean.
|
||||
static inline StringRef toStringRef(bool B) {
|
||||
return StringRef(B ? "true" : "false");
|
||||
}
|
||||
|
||||
/// Interpret the given character \p C as a hexadecimal digit and return its
|
||||
/// value.
|
||||
///
|
||||
@ -48,7 +53,7 @@ static inline unsigned hexDigitValue(char C) {
|
||||
/// This should only be used with unsigned types.
|
||||
///
|
||||
template<typename IntTy>
|
||||
static inline char *utohex_buffer(IntTy X, char *BufferEnd) {
|
||||
static inline char *utohex_buffer(IntTy X, char *BufferEnd, bool LowerCase = false) {
|
||||
char *BufPtr = BufferEnd;
|
||||
*--BufPtr = 0; // Null terminate buffer.
|
||||
if (X == 0) {
|
||||
@ -58,15 +63,15 @@ static inline char *utohex_buffer(IntTy X, char *BufferEnd) {
|
||||
|
||||
while (X) {
|
||||
unsigned char Mod = static_cast<unsigned char>(X) & 15;
|
||||
*--BufPtr = hexdigit(Mod);
|
||||
*--BufPtr = hexdigit(Mod, LowerCase);
|
||||
X >>= 4;
|
||||
}
|
||||
return BufPtr;
|
||||
}
|
||||
|
||||
static inline std::string utohexstr(uint64_t X) {
|
||||
static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||
char Buffer[17];
|
||||
return utohex_buffer(X, Buffer+17);
|
||||
return utohex_buffer(X, Buffer+17, LowerCase);
|
||||
}
|
||||
|
||||
static inline std::string utostr_32(uint32_t X, bool isNeg = false) {
|
||||
@ -136,7 +141,7 @@ void SplitString(StringRef Source,
|
||||
// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
|
||||
// X*33+c -> X*33^c
|
||||
static inline unsigned HashString(StringRef Str, unsigned Result = 0) {
|
||||
for (unsigned i = 0, e = Str.size(); i != e; ++i)
|
||||
for (StringRef::size_type i = 0, e = Str.size(); i != e; ++i)
|
||||
Result = Result * 33 + (unsigned char)Str[i];
|
||||
return Result;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
template<typename ValueT>
|
||||
@ -26,19 +27,6 @@ namespace llvm {
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry;
|
||||
|
||||
/// StringMapEntryInitializer - This datatype can be partially specialized for
|
||||
/// various datatypes in a stringmap to allow them to be initialized when an
|
||||
/// entry is default constructed for the map.
|
||||
template<typename ValueTy>
|
||||
class StringMapEntryInitializer {
|
||||
public:
|
||||
template <typename InitTy>
|
||||
static void Initialize(StringMapEntry<ValueTy> &T, InitTy InitVal) {
|
||||
T.second = InitVal;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||
class StringMapEntryBase {
|
||||
unsigned StrLen;
|
||||
@ -61,15 +49,22 @@ protected:
|
||||
unsigned NumTombstones;
|
||||
unsigned ItemSize;
|
||||
protected:
|
||||
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {
|
||||
// Initialize the map with zero buckets to allocation.
|
||||
TheTable = 0;
|
||||
NumBuckets = 0;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
explicit StringMapImpl(unsigned itemSize)
|
||||
: TheTable(nullptr),
|
||||
// Initialize the map with zero buckets to allocation.
|
||||
NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {}
|
||||
StringMapImpl(StringMapImpl &&RHS)
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
ItemSize(RHS.ItemSize) {
|
||||
RHS.TheTable = nullptr;
|
||||
RHS.NumBuckets = 0;
|
||||
RHS.NumItems = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
StringMapImpl(unsigned InitSize, unsigned ItemSize);
|
||||
void RehashTable();
|
||||
unsigned RehashTable(unsigned BucketNo = 0);
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
@ -122,8 +117,8 @@ public:
|
||||
|
||||
explicit StringMapEntry(unsigned strLen)
|
||||
: StringMapEntryBase(strLen), second() {}
|
||||
StringMapEntry(unsigned strLen, const ValueTy &V)
|
||||
: StringMapEntryBase(strLen), second(V) {}
|
||||
StringMapEntry(unsigned strLen, ValueTy V)
|
||||
: StringMapEntryBase(strLen), second(std::move(V)) {}
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), getKeyLength());
|
||||
@ -144,15 +139,13 @@ public:
|
||||
/// Create - Create a StringMapEntry for the specified key and default
|
||||
/// construct the value.
|
||||
template<typename AllocatorTy, typename InitType>
|
||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
|
||||
static StringMapEntry *Create(StringRef Key,
|
||||
AllocatorTy &Allocator,
|
||||
InitType InitVal) {
|
||||
unsigned KeyLength = static_cast<unsigned>(KeyEnd-KeyStart);
|
||||
unsigned KeyLength = Key.size();
|
||||
|
||||
// Okay, the item doesn't already exist, and 'Bucket' is the bucket to fill
|
||||
// in. Allocate a new item with space for the string at the end and a null
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
// terminator.
|
||||
|
||||
unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
|
||||
KeyLength+1;
|
||||
unsigned Alignment = alignOf<StringMapEntry>();
|
||||
@ -161,34 +154,29 @@ public:
|
||||
static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
|
||||
|
||||
// Default construct the value.
|
||||
new (NewItem) StringMapEntry(KeyLength);
|
||||
new (NewItem) StringMapEntry(KeyLength, std::move(InitVal));
|
||||
|
||||
// Copy the string information.
|
||||
char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
|
||||
memcpy(StrBuffer, KeyStart, KeyLength);
|
||||
memcpy(StrBuffer, Key.data(), KeyLength);
|
||||
StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
|
||||
|
||||
// Initialize the value if the client wants to.
|
||||
StringMapEntryInitializer<ValueTy>::Initialize(*NewItem, InitVal);
|
||||
return NewItem;
|
||||
}
|
||||
|
||||
template<typename AllocatorTy>
|
||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
|
||||
AllocatorTy &Allocator) {
|
||||
return Create(KeyStart, KeyEnd, Allocator, 0);
|
||||
static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator) {
|
||||
return Create(Key, Allocator, ValueTy());
|
||||
}
|
||||
|
||||
/// Create - Create a StringMapEntry with normal malloc/free.
|
||||
template<typename InitType>
|
||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
|
||||
InitType InitVal) {
|
||||
static StringMapEntry *Create(StringRef Key, InitType InitVal) {
|
||||
MallocAllocator A;
|
||||
return Create(KeyStart, KeyEnd, A, InitVal);
|
||||
return Create(Key, A, std::move(InitVal));
|
||||
}
|
||||
|
||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd) {
|
||||
return Create(KeyStart, KeyEnd, ValueTy());
|
||||
static StringMapEntry *Create(StringRef Key) {
|
||||
return Create(Key, ValueTy());
|
||||
}
|
||||
|
||||
/// GetStringMapEntryFromValue - Given a value that is known to be embedded
|
||||
@ -216,8 +204,10 @@ public:
|
||||
template<typename AllocatorTy>
|
||||
void Destroy(AllocatorTy &Allocator) {
|
||||
// Free memory referenced by the item.
|
||||
unsigned AllocSize =
|
||||
static_cast<unsigned>(sizeof(StringMapEntry)) + getKeyLength() + 1;
|
||||
this->~StringMapEntry();
|
||||
Allocator.Deallocate(this);
|
||||
Allocator.Deallocate(static_cast<void *>(this), AllocSize);
|
||||
}
|
||||
|
||||
/// Destroy this object, releasing memory back to the malloc allocator.
|
||||
@ -249,23 +239,19 @@ public:
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(A) {}
|
||||
|
||||
StringMap(const StringMap &RHS)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
assert(RHS.empty() &&
|
||||
"Copy ctor from non-empty stringmap not implemented yet!");
|
||||
(void)RHS;
|
||||
}
|
||||
void operator=(const StringMap &RHS) {
|
||||
assert(RHS.empty() &&
|
||||
"assignment from non-empty stringmap not implemented yet!");
|
||||
(void)RHS;
|
||||
clear();
|
||||
StringMap(StringMap &&RHS)
|
||||
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
std::swap(Allocator, RHS.Allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef typename ReferenceAdder<AllocatorTy>::result AllocatorRefTy;
|
||||
typedef typename ReferenceAdder<const AllocatorTy>::result AllocatorCRefTy;
|
||||
AllocatorRefTy getAllocator() { return Allocator; }
|
||||
AllocatorCRefTy getAllocator() const { return Allocator; }
|
||||
// FIXME: Implement copy operations if/when they're needed.
|
||||
|
||||
AllocatorTy &getAllocator() { return Allocator; }
|
||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||
|
||||
typedef const char* key_type;
|
||||
typedef ValueTy mapped_type;
|
||||
@ -313,6 +299,7 @@ public:
|
||||
return GetOrCreateValue(Key).getValue();
|
||||
}
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(StringRef Key) const {
|
||||
return find(Key) == end() ? 0 : 1;
|
||||
}
|
||||
@ -336,6 +323,28 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// insert - Inserts the specified key/value pair into the map if the key
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
|
||||
unsigned BucketNo = LookupBucketFor(KV.first);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false),
|
||||
false); // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket =
|
||||
MapEntryTy::Create(KV.first, Allocator, std::move(KV.second));
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
BucketNo = RehashTable(BucketNo);
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false), true);
|
||||
}
|
||||
|
||||
// clear - Empties out the StringMap
|
||||
void clear() {
|
||||
if (empty()) return;
|
||||
@ -347,7 +356,7 @@ public:
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
|
||||
}
|
||||
Bucket = 0;
|
||||
Bucket = nullptr;
|
||||
}
|
||||
|
||||
NumItems = 0;
|
||||
@ -359,25 +368,7 @@ public:
|
||||
/// return.
|
||||
template <typename InitTy>
|
||||
MapEntryTy &GetOrCreateValue(StringRef Key, InitTy Val) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return *static_cast<MapEntryTy*>(Bucket);
|
||||
|
||||
MapEntryTy *NewItem =
|
||||
MapEntryTy::Create(Key.begin(), Key.end(), Allocator, Val);
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
// Fill in the bucket for the hash table. The FullHashValue was already
|
||||
// filled in by LookupBucketFor.
|
||||
Bucket = NewItem;
|
||||
|
||||
RehashTable();
|
||||
return *NewItem;
|
||||
return *insert(std::make_pair(Key, std::move(Val))).first;
|
||||
}
|
||||
|
||||
MapEntryTy &GetOrCreateValue(StringRef Key) {
|
||||
@ -404,7 +395,17 @@ public:
|
||||
}
|
||||
|
||||
~StringMap() {
|
||||
clear();
|
||||
// Delete all the elements in the map, but don't reset the elements
|
||||
// to default values. This is a copy of clear(), but avoids unnecessary
|
||||
// work not required in the destructor.
|
||||
if (!empty()) {
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(TheTable);
|
||||
}
|
||||
};
|
||||
@ -417,7 +418,7 @@ protected:
|
||||
public:
|
||||
typedef StringMapEntry<ValueTy> value_type;
|
||||
|
||||
StringMapConstIterator() : Ptr(0) { }
|
||||
StringMapConstIterator() : Ptr(nullptr) { }
|
||||
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
@ -450,7 +451,7 @@ public:
|
||||
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
while (*Ptr == 0 || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
++Ptr;
|
||||
}
|
||||
};
|
||||
|
@ -10,7 +10,6 @@
|
||||
#ifndef LLVM_ADT_STRINGREF_H
|
||||
#define LLVM_ADT_STRINGREF_H
|
||||
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
@ -70,7 +69,7 @@ namespace llvm {
|
||||
/// @{
|
||||
|
||||
/// Construct an empty string ref.
|
||||
/*implicit*/ StringRef() : Data(0), Length(0) {}
|
||||
/*implicit*/ StringRef() : Data(nullptr), Length(0) {}
|
||||
|
||||
/// Construct a string ref from a cstring.
|
||||
/*implicit*/ StringRef(const char *Str)
|
||||
@ -124,6 +123,13 @@ namespace llvm {
|
||||
return Data[Length-1];
|
||||
}
|
||||
|
||||
// copy - Allocate copy in Allocator and return StringRef to it.
|
||||
template <typename Allocator> StringRef copy(Allocator &A) {
|
||||
char *S = A.template Allocate<char>(Length);
|
||||
std::copy(begin(), end(), S);
|
||||
return StringRef(S, Length);
|
||||
}
|
||||
|
||||
/// equals - Check for string equality, this is more efficient than
|
||||
/// compare() when the relative ordering of inequal strings isn't needed.
|
||||
bool equals(StringRef RHS) const {
|
||||
@ -179,7 +185,7 @@ namespace llvm {
|
||||
|
||||
/// str - Get the contents as an std::string.
|
||||
std::string str() const {
|
||||
if (Data == 0) return std::string();
|
||||
if (!Data) return std::string();
|
||||
return std::string(Data, Length);
|
||||
}
|
||||
|
||||
@ -333,7 +339,7 @@ namespace llvm {
|
||||
/// this returns true to signify the error. The string is considered
|
||||
/// erroneous if empty or if it overflows T.
|
||||
template <typename T>
|
||||
typename enable_if_c<std::numeric_limits<T>::is_signed, bool>::type
|
||||
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
|
||||
getAsInteger(unsigned Radix, T &Result) const {
|
||||
long long LLVal;
|
||||
if (getAsSignedInteger(*this, Radix, LLVal) ||
|
||||
@ -344,7 +350,7 @@ namespace llvm {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if_c<!std::numeric_limits<T>::is_signed, bool>::type
|
||||
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
|
||||
getAsInteger(unsigned Radix, T &Result) const {
|
||||
unsigned long long ULLVal;
|
||||
if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
|
||||
@ -553,11 +559,6 @@ namespace llvm {
|
||||
// StringRefs can be treated like a POD type.
|
||||
template <typename T> struct isPodLike;
|
||||
template <> struct isPodLike<StringRef> { static const bool value = true; };
|
||||
|
||||
/// Construct a string ref from a boolean.
|
||||
inline StringRef toStringRef(bool B) {
|
||||
return StringRef(B ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -49,7 +49,7 @@ class StringSwitch {
|
||||
|
||||
public:
|
||||
explicit StringSwitch(StringRef S)
|
||||
: Str(S), Result(0) { }
|
||||
: Str(S), Result(nullptr) { }
|
||||
|
||||
template<unsigned N>
|
||||
StringSwitch& Case(const char (&S)[N], const T& Value) {
|
||||
|
@ -12,9 +12,7 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -70,9 +68,8 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
|
||||
RHS.Val = (EltTy)0;
|
||||
RHS.Val = (EltTy)nullptr;
|
||||
}
|
||||
TinyPtrVector &operator=(TinyPtrVector &&RHS) {
|
||||
if (this == &RHS)
|
||||
@ -95,10 +92,9 @@ public:
|
||||
}
|
||||
|
||||
Val = RHS.Val;
|
||||
RHS.Val = (EltTy)0;
|
||||
RHS.Val = (EltTy)nullptr;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// implicit conversion operator to ArrayRef.
|
||||
operator ArrayRef<EltTy>() const {
|
||||
@ -178,7 +174,7 @@ public:
|
||||
}
|
||||
|
||||
void push_back(EltTy NewVal) {
|
||||
assert(NewVal != 0 && "Can't add a null value");
|
||||
assert(NewVal && "Can't add a null value");
|
||||
|
||||
// If we have nothing, add something.
|
||||
if (Val.isNull()) {
|
||||
@ -199,7 +195,7 @@ public:
|
||||
void pop_back() {
|
||||
// If we have a single value, convert to empty.
|
||||
if (Val.template is<EltTy>())
|
||||
Val = (EltTy)0;
|
||||
Val = (EltTy)nullptr;
|
||||
else if (VecTy *Vec = Val.template get<VecTy*>())
|
||||
Vec->pop_back();
|
||||
}
|
||||
@ -207,7 +203,7 @@ public:
|
||||
void clear() {
|
||||
// If we have a single value, convert to empty.
|
||||
if (Val.template is<EltTy>()) {
|
||||
Val = (EltTy)0;
|
||||
Val = (EltTy)nullptr;
|
||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||
// If we have a vector form, just clear it.
|
||||
Vec->clear();
|
||||
@ -222,7 +218,7 @@ public:
|
||||
// If we have a single value, convert to empty.
|
||||
if (Val.template is<EltTy>()) {
|
||||
if (I == begin())
|
||||
Val = (EltTy)0;
|
||||
Val = (EltTy)nullptr;
|
||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||
// multiple items in a vector; just do the erase, there is no
|
||||
// benefit to collapsing back to a pointer
|
||||
@ -238,7 +234,7 @@ public:
|
||||
|
||||
if (Val.template is<EltTy>()) {
|
||||
if (S == begin() && S != E)
|
||||
Val = (EltTy)0;
|
||||
Val = (EltTy)nullptr;
|
||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||
return Vec->erase(S, E);
|
||||
}
|
||||
@ -250,7 +246,7 @@ public:
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
if (I == end()) {
|
||||
push_back(Elt);
|
||||
return llvm::prior(end());
|
||||
return std::prev(end());
|
||||
}
|
||||
assert(!Val.isNull() && "Null value with non-end insert iterator.");
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||
@ -273,7 +269,7 @@ public:
|
||||
// If we have a single value, convert to a vector.
|
||||
ptrdiff_t Offset = I - begin();
|
||||
if (Val.isNull()) {
|
||||
if (llvm::next(From) == To) {
|
||||
if (std::next(From) == To) {
|
||||
Val = *From;
|
||||
return begin();
|
||||
}
|
||||
|
@ -46,32 +46,53 @@ public:
|
||||
enum ArchType {
|
||||
UnknownArch,
|
||||
|
||||
arm, // ARM: arm, armv.*, xscale
|
||||
aarch64, // AArch64: aarch64
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
mips64, // MIPS64: mips64
|
||||
mips64el,// MIPS64EL: mips64el
|
||||
msp430, // MSP430: msp430
|
||||
ppc, // PPC: powerpc
|
||||
ppc64, // PPC64: powerpc64, ppu
|
||||
ppc64le, // PPC64LE: powerpc64le
|
||||
r600, // R600: AMD GPUs HD2XXX - HD6XXX
|
||||
sparc, // Sparc: sparc
|
||||
sparcv9, // Sparcv9: Sparcv9
|
||||
systemz, // SystemZ: s390x
|
||||
tce, // TCE (http://tce.cs.tut.fi/): tce
|
||||
thumb, // Thumb: thumb, thumbv.*
|
||||
x86, // X86: i[3-9]86
|
||||
x86_64, // X86-64: amd64, x86_64
|
||||
xcore, // XCore: xcore
|
||||
nvptx, // NVPTX: 32-bit
|
||||
nvptx64, // NVPTX: 64-bit
|
||||
le32, // le32: generic little-endian 32-bit CPU (PNaCl / Emscripten)
|
||||
amdil, // amdil: amd IL
|
||||
spir, // SPIR: standard portable IR for OpenCL 32-bit version
|
||||
spir64 // SPIR: standard portable IR for OpenCL 64-bit version
|
||||
arm, // ARM (little endian): arm, armv.*, xscale
|
||||
armeb, // ARM (big endian): armeb
|
||||
arm64, // ARM64 (little endian): arm64
|
||||
arm64_be, // ARM64 (big endian): arm64_be
|
||||
aarch64, // AArch64 (little endian): aarch64
|
||||
aarch64_be, // AArch64 (big endian): aarch64_be
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
mips64, // MIPS64: mips64
|
||||
mips64el, // MIPS64EL: mips64el
|
||||
msp430, // MSP430: msp430
|
||||
ppc, // PPC: powerpc
|
||||
ppc64, // PPC64: powerpc64, ppu
|
||||
ppc64le, // PPC64LE: powerpc64le
|
||||
r600, // R600: AMD GPUs HD2XXX - HD6XXX
|
||||
sparc, // Sparc: sparc
|
||||
sparcv9, // Sparcv9: Sparcv9
|
||||
systemz, // SystemZ: s390x
|
||||
tce, // TCE (http://tce.cs.tut.fi/): tce
|
||||
thumb, // Thumb (little endian): thumb, thumbv.*
|
||||
thumbeb, // Thumb (big endian): thumbeb
|
||||
x86, // X86: i[3-9]86
|
||||
x86_64, // X86-64: amd64, x86_64
|
||||
xcore, // XCore: xcore
|
||||
nvptx, // NVPTX: 32-bit
|
||||
nvptx64, // NVPTX: 64-bit
|
||||
le32, // le32: generic little-endian 32-bit CPU (PNaCl / Emscripten)
|
||||
amdil, // amdil: amd IL
|
||||
spir, // SPIR: standard portable IR for OpenCL 32-bit version
|
||||
spir64, // SPIR: standard portable IR for OpenCL 64-bit version
|
||||
kalimba // Kalimba: generic kalimba
|
||||
};
|
||||
enum SubArchType {
|
||||
NoSubArch,
|
||||
|
||||
ARMSubArch_v8,
|
||||
ARMSubArch_v7,
|
||||
ARMSubArch_v7em,
|
||||
ARMSubArch_v7m,
|
||||
ARMSubArch_v7s,
|
||||
ARMSubArch_v6,
|
||||
ARMSubArch_v6m,
|
||||
ARMSubArch_v6t2,
|
||||
ARMSubArch_v5,
|
||||
ARMSubArch_v5te,
|
||||
ARMSubArch_v4t
|
||||
};
|
||||
enum VendorType {
|
||||
UnknownVendor,
|
||||
@ -83,7 +104,10 @@ public:
|
||||
BGQ,
|
||||
Freescale,
|
||||
IBM,
|
||||
NVIDIA
|
||||
ImaginationTechnologies,
|
||||
MipsTechnologies,
|
||||
NVIDIA,
|
||||
CSR
|
||||
};
|
||||
enum OSType {
|
||||
UnknownOS,
|
||||
@ -120,10 +144,21 @@ public:
|
||||
GNUEABI,
|
||||
GNUEABIHF,
|
||||
GNUX32,
|
||||
CODE16,
|
||||
EABI,
|
||||
MachO,
|
||||
EABIHF,
|
||||
Android,
|
||||
ELF
|
||||
|
||||
MSVC,
|
||||
Itanium,
|
||||
Cygnus,
|
||||
};
|
||||
enum ObjectFormatType {
|
||||
UnknownObjectFormat,
|
||||
|
||||
COFF,
|
||||
ELF,
|
||||
MachO,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -132,6 +167,9 @@ private:
|
||||
/// The parsed arch type.
|
||||
ArchType Arch;
|
||||
|
||||
/// The parsed subarchitecture type.
|
||||
SubArchType SubArch;
|
||||
|
||||
/// The parsed vendor type.
|
||||
VendorType Vendor;
|
||||
|
||||
@ -141,13 +179,16 @@ private:
|
||||
/// The parsed Environment type.
|
||||
EnvironmentType Environment;
|
||||
|
||||
/// The object format type.
|
||||
ObjectFormatType ObjectFormat;
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
|
||||
/// \brief Default constructor is the same as an empty string and leaves all
|
||||
/// triple fields unknown.
|
||||
Triple() : Data(), Arch(), Vendor(), OS(), Environment() {}
|
||||
Triple() : Data(), Arch(), Vendor(), OS(), Environment(), ObjectFormat() {}
|
||||
|
||||
explicit Triple(const Twine &Str);
|
||||
Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr);
|
||||
@ -171,6 +212,9 @@ public:
|
||||
/// getArch - Get the parsed architecture type of this triple.
|
||||
ArchType getArch() const { return Arch; }
|
||||
|
||||
/// getSubArch - get the parsed subarchitecture type for this triple.
|
||||
SubArchType getSubArch() const { return SubArch; }
|
||||
|
||||
/// getVendor - Get the parsed vendor type of this triple.
|
||||
VendorType getVendor() const { return Vendor; }
|
||||
|
||||
@ -186,6 +230,9 @@ public:
|
||||
/// getEnvironment - Get the parsed environment type of this triple.
|
||||
EnvironmentType getEnvironment() const { return Environment; }
|
||||
|
||||
/// getFormat - Get the object format for this triple.
|
||||
ObjectFormatType getObjectFormat() const { return ObjectFormat; }
|
||||
|
||||
/// getOSVersion - Parse the version number from the OS name component of the
|
||||
/// triple, if present.
|
||||
///
|
||||
@ -314,14 +361,42 @@ public:
|
||||
return isMacOSX() || isiOS();
|
||||
}
|
||||
|
||||
bool isOSFreeBSD() const {
|
||||
return getOS() == Triple::FreeBSD;
|
||||
}
|
||||
|
||||
bool isWindowsMSVCEnvironment() const {
|
||||
return getOS() == Triple::Win32 &&
|
||||
(getEnvironment() == Triple::UnknownEnvironment ||
|
||||
getEnvironment() == Triple::MSVC);
|
||||
}
|
||||
|
||||
bool isKnownWindowsMSVCEnvironment() const {
|
||||
return getOS() == Triple::Win32 && getEnvironment() == Triple::MSVC;
|
||||
}
|
||||
|
||||
bool isWindowsItaniumEnvironment() const {
|
||||
return getOS() == Triple::Win32 && getEnvironment() == Triple::Itanium;
|
||||
}
|
||||
|
||||
bool isWindowsCygwinEnvironment() const {
|
||||
return getOS() == Triple::Cygwin ||
|
||||
(getOS() == Triple::Win32 && getEnvironment() == Triple::Cygnus);
|
||||
}
|
||||
|
||||
bool isWindowsGNUEnvironment() const {
|
||||
return getOS() == Triple::MinGW32 ||
|
||||
(getOS() == Triple::Win32 && getEnvironment() == Triple::GNU);
|
||||
}
|
||||
|
||||
/// \brief Tests for either Cygwin or MinGW OS
|
||||
bool isOSCygMing() const {
|
||||
return getOS() == Triple::Cygwin || getOS() == Triple::MinGW32;
|
||||
return isWindowsCygwinEnvironment() || isWindowsGNUEnvironment();
|
||||
}
|
||||
|
||||
/// \brief Is this a "Windows" OS targeting a "MSVCRT.dll" environment.
|
||||
bool isOSMSVCRT() const {
|
||||
return getOS() == Triple::Win32 || getOS() == Triple::MinGW32;
|
||||
return isWindowsMSVCEnvironment() || isWindowsGNUEnvironment();
|
||||
}
|
||||
|
||||
/// \brief Tests whether the OS is Windows.
|
||||
@ -341,18 +416,17 @@ public:
|
||||
|
||||
/// \brief Tests whether the OS uses the ELF binary format.
|
||||
bool isOSBinFormatELF() const {
|
||||
return !isOSDarwin() && !isOSWindows();
|
||||
return getObjectFormat() == Triple::ELF;
|
||||
}
|
||||
|
||||
/// \brief Tests whether the OS uses the COFF binary format.
|
||||
bool isOSBinFormatCOFF() const {
|
||||
return isOSWindows();
|
||||
return getObjectFormat() == Triple::COFF;
|
||||
}
|
||||
|
||||
/// \brief Tests whether the environment is MachO.
|
||||
// FIXME: Should this be an OSBinFormat predicate?
|
||||
bool isEnvironmentMachO() const {
|
||||
return getEnvironment() == Triple::MachO || isOSDarwin();
|
||||
bool isOSBinFormatMachO() const {
|
||||
return getObjectFormat() == Triple::MachO;
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -375,6 +449,9 @@ public:
|
||||
/// to a known type.
|
||||
void setEnvironment(EnvironmentType Kind);
|
||||
|
||||
/// setObjectFormat - Set the object file format
|
||||
void setObjectFormat(ObjectFormatType Kind);
|
||||
|
||||
/// setTriple - Set all components to the new triple \p Str.
|
||||
void setTriple(const Twine &Str);
|
||||
|
||||
@ -422,6 +499,12 @@ public:
|
||||
/// architecture if no such variant can be found.
|
||||
llvm::Triple get64BitArchVariant() const;
|
||||
|
||||
/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
|
||||
///
|
||||
/// \param Arch the architecture name (e.g., "armv7s"). If it is an empty
|
||||
/// string then the triple's arch name is used.
|
||||
const char* getARMCPUForArch(StringRef Arch = StringRef()) const;
|
||||
|
||||
/// @}
|
||||
/// @name Static helpers for IDs.
|
||||
/// @{
|
||||
|
@ -182,6 +182,10 @@ namespace llvm {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Since the intended use of twines is as temporary objects, assignments
|
||||
/// when concatenating might cause undefined behavior or stack corruptions
|
||||
Twine &operator=(const Twine &Other) LLVM_DELETED_FUNCTION;
|
||||
|
||||
/// isNull - Check for the null twine.
|
||||
bool isNull() const {
|
||||
return getLHSKind() == NullKind;
|
||||
@ -374,7 +378,7 @@ namespace llvm {
|
||||
static Twine utohexstr(const uint64_t &Val) {
|
||||
Child LHS, RHS;
|
||||
LHS.uHex = &Val;
|
||||
RHS.twine = 0;
|
||||
RHS.twine = nullptr;
|
||||
return Twine(LHS, UHexKind, RHS, EmptyKind);
|
||||
}
|
||||
|
||||
|
@ -22,13 +22,18 @@ namespace llvm {
|
||||
/// class should have an implementation of operator== and of operator<.
|
||||
/// Entries can be fetched using operator[] with the entry ID.
|
||||
template<class T> class UniqueVector {
|
||||
public:
|
||||
typedef typename std::vector<T> VectorType;
|
||||
typedef typename VectorType::iterator iterator;
|
||||
typedef typename VectorType::const_iterator const_iterator;
|
||||
|
||||
private:
|
||||
// Map - Used to handle the correspondence of entry to ID.
|
||||
std::map<T, unsigned> Map;
|
||||
|
||||
// Vector - ID ordered vector of entries. Entries can be indexed by ID - 1.
|
||||
//
|
||||
std::vector<T> Vector;
|
||||
VectorType Vector;
|
||||
|
||||
public:
|
||||
/// insert - Append entry to the vector if it doesn't already exist. Returns
|
||||
@ -68,6 +73,18 @@ public:
|
||||
return Vector[ID - 1];
|
||||
}
|
||||
|
||||
/// \brief Return an iterator to the start of the vector.
|
||||
iterator begin() { return Vector.begin(); }
|
||||
|
||||
/// \brief Return an iterator to the start of the vector.
|
||||
const_iterator begin() const { return Vector.begin(); }
|
||||
|
||||
/// \brief Return an iterator to the end of the vector.
|
||||
iterator end() { return Vector.end(); }
|
||||
|
||||
/// \brief Return an iterator to the end of the vector.
|
||||
const_iterator end() const { return Vector.end(); }
|
||||
|
||||
/// size - Returns the number of entries in the vector.
|
||||
///
|
||||
size_t size() const { return Vector.size(); }
|
||||
|
@ -17,8 +17,8 @@
|
||||
#define LLVM_ADT_EDIT_DISTANCE_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -57,7 +57,7 @@ unsigned ComputeEditDistance(ArrayRef<T> FromArray, ArrayRef<T> ToArray,
|
||||
|
||||
const unsigned SmallBufferSize = 64;
|
||||
unsigned SmallBuffer[SmallBufferSize];
|
||||
llvm::OwningArrayPtr<unsigned> Allocated;
|
||||
std::unique_ptr<unsigned[]> Allocated;
|
||||
unsigned *Previous = SmallBuffer;
|
||||
if (2*(n + 1) > SmallBufferSize) {
|
||||
Previous = new unsigned [2*(n+1)];
|
||||
|
@ -83,7 +83,7 @@ struct ilist_sentinel_traits {
|
||||
/// provideInitialHead - when constructing an ilist, provide a starting
|
||||
/// value for its Head
|
||||
/// @return null node to indicate that it needs to be allocated later
|
||||
static NodeTy *provideInitialHead() { return 0; }
|
||||
static NodeTy *provideInitialHead() { return nullptr; }
|
||||
|
||||
/// ensureHead - make sure that Head is either already
|
||||
/// initialized or assigned a fresh sentinel
|
||||
@ -92,7 +92,7 @@ struct ilist_sentinel_traits {
|
||||
if (!Head) {
|
||||
Head = ilist_traits<NodeTy>::createSentinel();
|
||||
ilist_traits<NodeTy>::noteHead(Head, Head);
|
||||
ilist_traits<NodeTy>::setNext(Head, 0);
|
||||
ilist_traits<NodeTy>::setNext(Head, nullptr);
|
||||
return Head;
|
||||
}
|
||||
return ilist_traits<NodeTy>::getPrev(Head);
|
||||
@ -175,7 +175,7 @@ public:
|
||||
|
||||
ilist_iterator(pointer NP) : NodePtr(NP) {}
|
||||
ilist_iterator(reference NR) : NodePtr(&NR) {}
|
||||
ilist_iterator() : NodePtr(0) {}
|
||||
ilist_iterator() : NodePtr(nullptr) {}
|
||||
|
||||
// This is templated so that we can allow constructing a const iterator from
|
||||
// a nonconst iterator...
|
||||
@ -383,7 +383,7 @@ public:
|
||||
// Miscellaneous inspection routines.
|
||||
size_type max_size() const { return size_type(-1); }
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||
return Head == 0 || Head == getTail();
|
||||
return !Head || Head == getTail();
|
||||
}
|
||||
|
||||
// Front and back accessor functions...
|
||||
@ -451,8 +451,8 @@ public:
|
||||
// an ilist (and potentially deleted) with iterators still pointing at it.
|
||||
// When those iterators are incremented or decremented, they will assert on
|
||||
// the null next/prev pointer instead of "usually working".
|
||||
this->setNext(Node, 0);
|
||||
this->setPrev(Node, 0);
|
||||
this->setNext(Node, nullptr);
|
||||
this->setPrev(Node, nullptr);
|
||||
return Node;
|
||||
}
|
||||
|
||||
@ -494,9 +494,9 @@ private:
|
||||
// Note: we have to be careful about the case when we move the first node
|
||||
// in the list. This node is the list sentinel node and we can't move it.
|
||||
NodeTy *ThisSentinel = getTail();
|
||||
setTail(0);
|
||||
setTail(nullptr);
|
||||
NodeTy *L2Sentinel = L2.getTail();
|
||||
L2.setTail(0);
|
||||
L2.setTail(nullptr);
|
||||
|
||||
// Remove [first, last) from its old position.
|
||||
NodeTy *First = &*first, *Prev = this->getPrev(First);
|
||||
@ -537,7 +537,7 @@ public:
|
||||
//
|
||||
|
||||
size_type LLVM_ATTRIBUTE_UNUSED_RESULT size() const {
|
||||
if (Head == 0) return 0; // Don't require construction of sentinel if empty.
|
||||
if (!Head) return 0; // Don't require construction of sentinel if empty.
|
||||
return std::distance(begin(), end());
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ protected:
|
||||
NodeTy *getPrev() { return Prev; }
|
||||
const NodeTy *getPrev() const { return Prev; }
|
||||
void setPrev(NodeTy *P) { Prev = P; }
|
||||
ilist_half_node() : Prev(0) {}
|
||||
ilist_half_node() : Prev(nullptr) {}
|
||||
};
|
||||
|
||||
template<typename NodeTy>
|
||||
@ -48,7 +48,7 @@ class ilist_node : private ilist_half_node<NodeTy> {
|
||||
const NodeTy *getNext() const { return Next; }
|
||||
void setNext(NodeTy *N) { Next = N; }
|
||||
protected:
|
||||
ilist_node() : Next(0) {}
|
||||
ilist_node() : Next(nullptr) {}
|
||||
|
||||
public:
|
||||
/// @name Adjacent Node Accessors
|
||||
@ -60,7 +60,7 @@ public:
|
||||
|
||||
// Check for sentinel.
|
||||
if (!Prev->getNext())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return Prev;
|
||||
}
|
||||
@ -71,7 +71,7 @@ public:
|
||||
|
||||
// Check for sentinel.
|
||||
if (!Prev->getNext())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return Prev;
|
||||
}
|
||||
@ -82,7 +82,7 @@ public:
|
||||
|
||||
// Check for sentinel.
|
||||
if (!Next->getNext())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return Next;
|
||||
}
|
||||
@ -93,7 +93,7 @@ public:
|
||||
|
||||
// Check for sentinel.
|
||||
if (!Next->getNext())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return Next;
|
||||
}
|
||||
|
244
contrib/llvm/include/llvm/ADT/iterator.h
Normal file
244
contrib/llvm/include/llvm/ADT/iterator.h
Normal file
@ -0,0 +1,244 @@
|
||||
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_ITERATOR_H
|
||||
#define LLVM_ADT_ITERATOR_H
|
||||
|
||||
#include <iterator>
|
||||
#include <cstddef>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief CRTP base class which implements the entire standard iterator facade
|
||||
/// in terms of a minimal subset of the interface.
|
||||
///
|
||||
/// Use this when it is reasonable to implement most of the iterator
|
||||
/// functionality in terms of a core subset. If you need special behavior or
|
||||
/// there are performance implications for this, you may want to override the
|
||||
/// relevant members instead.
|
||||
///
|
||||
/// Note, one abstraction that this does *not* provide is implementing
|
||||
/// subtraction in terms of addition by negating the difference. Negation isn't
|
||||
/// always information preserving, and I can see very reasonable iterator
|
||||
/// designs where this doesn't work well. It doesn't really force much added
|
||||
/// boilerplate anyways.
|
||||
///
|
||||
/// Another abstraction that this doesn't provide is implementing increment in
|
||||
/// terms of addition of one. These aren't equivalent for all iterator
|
||||
/// categories, and respecting that adds a lot of complexity for little gain.
|
||||
template <typename DerivedT, typename IteratorCategoryT, typename T,
|
||||
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
|
||||
typename ReferenceT = T &>
|
||||
class iterator_facade_base
|
||||
: public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
|
||||
ReferenceT> {
|
||||
protected:
|
||||
enum {
|
||||
IsRandomAccess =
|
||||
std::is_base_of<std::random_access_iterator_tag, IteratorCategoryT>::value,
|
||||
IsBidirectional =
|
||||
std::is_base_of<std::bidirectional_iterator_tag, IteratorCategoryT>::value,
|
||||
};
|
||||
|
||||
public:
|
||||
DerivedT operator+(DifferenceTypeT n) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp += n;
|
||||
return tmp;
|
||||
}
|
||||
friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
return i + n;
|
||||
}
|
||||
DerivedT operator-(DifferenceTypeT n) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp -= n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
DerivedT &operator++() {
|
||||
return static_cast<DerivedT *>(this)->operator+=(1);
|
||||
}
|
||||
DerivedT operator++(int) {
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
++*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
return static_cast<DerivedT *>(this)->operator-=(1);
|
||||
}
|
||||
DerivedT operator--(int) {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
--*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator!=(const DerivedT &RHS) const {
|
||||
return !static_cast<const DerivedT *>(this)->operator==(RHS);
|
||||
}
|
||||
|
||||
bool operator>(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
|
||||
!static_cast<const DerivedT *>(this)->operator==(RHS);
|
||||
}
|
||||
bool operator<=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !static_cast<const DerivedT *>(this)->operator>(RHS);
|
||||
}
|
||||
bool operator>=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !static_cast<const DerivedT *>(this)->operator<(RHS);
|
||||
}
|
||||
|
||||
PointerT operator->() const {
|
||||
return &static_cast<const DerivedT *>(this)->operator*();
|
||||
}
|
||||
ReferenceT operator[](DifferenceTypeT n) const {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return *static_cast<const DerivedT *>(this)->operator+(n);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief CRTP base class for adapting an iterator to a different type.
|
||||
///
|
||||
/// This class can be used through CRTP to adapt one iterator into another.
|
||||
/// Typically this is done through providing in the derived class a custom \c
|
||||
/// operator* implementation. Other methods can be overridden as well.
|
||||
template <
|
||||
typename DerivedT, typename WrappedIteratorT,
|
||||
typename IteratorCategoryT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
|
||||
typename DifferenceTypeT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::difference_type,
|
||||
typename PointerT = T *, typename ReferenceT = T &,
|
||||
// Don't provide these, they are mostly to act as aliases below.
|
||||
typename WrappedTraitsT = std::iterator_traits<WrappedIteratorT>>
|
||||
class iterator_adaptor_base
|
||||
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
|
||||
DifferenceTypeT, PointerT, ReferenceT> {
|
||||
typedef typename iterator_adaptor_base::iterator_facade_base BaseT;
|
||||
|
||||
protected:
|
||||
WrappedIteratorT I;
|
||||
|
||||
iterator_adaptor_base() {}
|
||||
|
||||
template <typename U>
|
||||
explicit iterator_adaptor_base(
|
||||
U &&u,
|
||||
typename std::enable_if<
|
||||
!std::is_base_of<typename std::remove_cv<
|
||||
typename std::remove_reference<U>::type>::type,
|
||||
DerivedT>::value,
|
||||
int>::type = 0)
|
||||
: I(std::forward<U &&>(u)) {}
|
||||
|
||||
public:
|
||||
typedef DifferenceTypeT difference_type;
|
||||
|
||||
DerivedT &operator+=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '+=' operator is only defined for random access iterators.");
|
||||
I += n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
DerivedT &operator-=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-=' operator is only defined for random access iterators.");
|
||||
I -= n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator-;
|
||||
difference_type operator-(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
return I - RHS.I;
|
||||
}
|
||||
|
||||
// We have to explicitly provide ++ and -- rather than letting the facade
|
||||
// forward to += because WrappedIteratorT might not support +=.
|
||||
using BaseT::operator++;
|
||||
DerivedT &operator++() {
|
||||
++I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator--;
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
BaseT::IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
--I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
|
||||
bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
|
||||
bool operator<(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return I < RHS.I;
|
||||
}
|
||||
|
||||
ReferenceT operator*() const { return *I; }
|
||||
};
|
||||
|
||||
/// \brief An iterator type that allows iterating over the pointees via some
|
||||
/// other iterator.
|
||||
///
|
||||
/// The typical usage of this is to expose a type that iterates over Ts, but
|
||||
/// which is implemented with some iterator over T*s:
|
||||
///
|
||||
/// \code
|
||||
/// typedef pointee_iterator<SmallVectorImpl<T *>::iterator> iterator;
|
||||
/// \endcode
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = typename std::remove_reference<
|
||||
decltype(**std::declval<WrappedIteratorT>())>::type>
|
||||
struct pointee_iterator
|
||||
: iterator_adaptor_base<
|
||||
pointee_iterator<WrappedIteratorT>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
pointee_iterator() {}
|
||||
template <typename U>
|
||||
pointee_iterator(U &&u)
|
||||
: pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
|
||||
|
||||
T &operator*() const { return **this->I; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
53
contrib/llvm/include/llvm/ADT/iterator_range.h
Normal file
53
contrib/llvm/include/llvm/ADT/iterator_range.h
Normal file
@ -0,0 +1,53 @@
|
||||
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This provides a very simple, boring adaptor for a begin and end iterator
|
||||
/// into a range type. This should be used to build range views that work well
|
||||
/// with range based for loops and range based constructors.
|
||||
///
|
||||
/// Note that code here follows more standards-based coding conventions as it
|
||||
/// is mirroring proposed interfaces for standardization.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_ITERATOR_RANGE_H
|
||||
#define LLVM_ADT_ITERATOR_RANGE_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief A range adaptor for a pair of iterators.
|
||||
///
|
||||
/// This just wraps two iterators into a range-compatible interface. Nothing
|
||||
/// fancy at all.
|
||||
template <typename IteratorT>
|
||||
class iterator_range {
|
||||
IteratorT begin_iterator, end_iterator;
|
||||
|
||||
public:
|
||||
iterator_range() {}
|
||||
iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
|
||||
: begin_iterator(std::move(begin_iterator)),
|
||||
end_iterator(std::move(end_iterator)) {}
|
||||
|
||||
IteratorT begin() const { return begin_iterator; }
|
||||
IteratorT end() const { return end_iterator; }
|
||||
};
|
||||
|
||||
/// \brief Convenience function for iterating over sub-ranges.
|
||||
///
|
||||
/// This provides a bit of syntactic sugar to make using sub-ranges
|
||||
/// in for loops a bit easier. Analogous to std::make_pair().
|
||||
template <class T> iterator_range<T> make_range(T x, T y) {
|
||||
return iterator_range<T>(std::move(x), std::move(y));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,117 +0,0 @@
|
||||
//===- llvm/ADT/polymorphic_ptr.h - Smart copyable owned ptr ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file provides a polymorphic_ptr class template. See the class comments
|
||||
/// for details about this API, its intended use cases, etc.
|
||||
///
|
||||
/// The primary motivation here is to work around the necessity of copy
|
||||
/// semantics in C++98. This is typically used where any actual copies are
|
||||
/// incidental or unnecessary. As a consequence, it is expected to cease to be
|
||||
/// useful and be removed when we can directly rely on move-only types.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_POLYMORPHIC_PTR_H
|
||||
#define LLVM_ADT_POLYMORPHIC_PTR_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief An owning, copyable polymorphic smart pointer.
|
||||
///
|
||||
/// This pointer exists to provide copyable owned smart pointer. Rather than
|
||||
/// shared ownership semantics, it has unique ownership semantics and deep copy
|
||||
/// semantics. It is copyable by requiring that the underlying type exposes
|
||||
/// a method which can produce a (heap allocated) clone.
|
||||
///
|
||||
/// Note that in almost all scenarios use of this could be avoided if we could
|
||||
/// build move-only containers of a std::unique_ptr, but until then this
|
||||
/// provides an effective way to place polymorphic objects in a container.
|
||||
template <typename T> class polymorphic_ptr {
|
||||
T *ptr;
|
||||
|
||||
public:
|
||||
polymorphic_ptr(T *ptr = 0) : ptr(ptr) {}
|
||||
polymorphic_ptr(const polymorphic_ptr &arg) : ptr(arg ? arg->clone() : 0) {}
|
||||
#if LLVM_HAS_RVALUE_REFERENCES
|
||||
polymorphic_ptr(polymorphic_ptr &&arg) : ptr(arg.take()) {}
|
||||
#endif
|
||||
~polymorphic_ptr() { delete ptr; }
|
||||
|
||||
polymorphic_ptr &operator=(polymorphic_ptr arg) {
|
||||
swap(arg);
|
||||
return *this;
|
||||
}
|
||||
polymorphic_ptr &operator=(T *arg) {
|
||||
if (arg != ptr) {
|
||||
delete ptr;
|
||||
ptr = arg;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T &operator*() const { return *ptr; }
|
||||
T *operator->() const { return ptr; }
|
||||
LLVM_EXPLICIT operator bool() const { return ptr != 0; }
|
||||
bool operator!() const { return ptr == 0; }
|
||||
|
||||
T *get() const { return ptr; }
|
||||
|
||||
T *take() {
|
||||
T *tmp = ptr;
|
||||
ptr = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void swap(polymorphic_ptr &arg) {
|
||||
T *tmp = ptr;
|
||||
ptr = arg.ptr;
|
||||
arg.ptr = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void swap(polymorphic_ptr<T> &lhs, polymorphic_ptr<T> &rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const polymorphic_ptr<T> &lhs, const polymorphic_ptr<U> &rhs) {
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const polymorphic_ptr<T> &lhs, const polymorphic_ptr<U> &rhs) {
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const polymorphic_ptr<T> &lhs, U *rhs) {
|
||||
return lhs.get() == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const polymorphic_ptr<T> &lhs, U *rhs) {
|
||||
return lhs.get() != rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(T *lhs, const polymorphic_ptr<U> &rhs) {
|
||||
return lhs == rhs.get();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(T *lhs, const polymorphic_ptr<U> &rhs) {
|
||||
return lhs != rhs.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -38,7 +38,7 @@
|
||||
#define LLVM_ANALYSIS_ALIASANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -55,7 +55,7 @@ class DominatorTree;
|
||||
|
||||
class AliasAnalysis {
|
||||
protected:
|
||||
const DataLayout *TD;
|
||||
const DataLayout *DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
|
||||
private:
|
||||
@ -75,7 +75,7 @@ protected:
|
||||
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
AliasAnalysis() : TD(0), TLI(0), AA(0) {}
|
||||
AliasAnalysis() : DL(nullptr), TLI(nullptr), AA(nullptr) {}
|
||||
virtual ~AliasAnalysis(); // We want to be subclassed
|
||||
|
||||
/// UnknownSize - This is a special value which can be used with the
|
||||
@ -86,7 +86,7 @@ public:
|
||||
/// getDataLayout - Return a pointer to the current DataLayout object, or
|
||||
/// null if no DataLayout object is available.
|
||||
///
|
||||
const DataLayout *getDataLayout() const { return TD; }
|
||||
const DataLayout *getDataLayout() const { return DL; }
|
||||
|
||||
/// getTargetLibraryInfo - Return a pointer to the current TargetLibraryInfo
|
||||
/// object, or null if no TargetLibraryInfo object is available.
|
||||
@ -116,8 +116,8 @@ public:
|
||||
/// the location, or null if there is no known unique tag.
|
||||
const MDNode *TBAATag;
|
||||
|
||||
explicit Location(const Value *P = 0, uint64_t S = UnknownSize,
|
||||
const MDNode *N = 0)
|
||||
explicit Location(const Value *P = nullptr, uint64_t S = UnknownSize,
|
||||
const MDNode *N = nullptr)
|
||||
: Ptr(P), Size(S), TBAATag(N) {}
|
||||
|
||||
Location getWithNewPtr(const Value *NewPtr) const {
|
||||
@ -134,7 +134,7 @@ public:
|
||||
|
||||
Location getWithoutTBAATag() const {
|
||||
Location Copy(*this);
|
||||
Copy.TBAATag = 0;
|
||||
Copy.TBAATag = nullptr;
|
||||
return Copy;
|
||||
}
|
||||
};
|
||||
@ -274,6 +274,14 @@ public:
|
||||
UnknownModRefBehavior = Anywhere | ModRef
|
||||
};
|
||||
|
||||
/// Get the location associated with a pointer argument of a callsite.
|
||||
/// The mask bits are set to indicate the allowed aliasing ModRef kinds.
|
||||
/// Note that these mask bits do not necessarily account for the overall
|
||||
/// behavior of the function, but rather only provide additional
|
||||
/// per-argument information.
|
||||
virtual Location getArgLocation(ImmutableCallSite CS, unsigned ArgIdx,
|
||||
ModRefResult &Mask);
|
||||
|
||||
/// getModRefBehavior - Return the behavior when calling the given call site.
|
||||
virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
|
||||
@ -560,12 +568,12 @@ struct DenseMapInfo<AliasAnalysis::Location> {
|
||||
static inline AliasAnalysis::Location getEmptyKey() {
|
||||
return
|
||||
AliasAnalysis::Location(DenseMapInfo<const Value *>::getEmptyKey(),
|
||||
0, 0);
|
||||
0, nullptr);
|
||||
}
|
||||
static inline AliasAnalysis::Location getTombstoneKey() {
|
||||
return
|
||||
AliasAnalysis::Location(DenseMapInfo<const Value *>::getTombstoneKey(),
|
||||
0, 0);
|
||||
0, nullptr);
|
||||
}
|
||||
static unsigned getHashValue(const AliasAnalysis::Location &Val) {
|
||||
return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^
|
||||
@ -597,6 +605,13 @@ bool isNoAliasArgument(const Value *V);
|
||||
///
|
||||
bool isIdentifiedObject(const Value *V);
|
||||
|
||||
/// isIdentifiedFunctionLocal - Return true if V is umabigously identified
|
||||
/// at the function-level. Different IdentifiedFunctionLocals can't alias.
|
||||
/// Further, an IdentifiedFunctionLocal can not alias with any function
|
||||
/// arguments other than itself, which is not necessarily true for
|
||||
/// IdentifiedObjects.
|
||||
bool isIdentifiedFunctionLocal(const Value *V);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/ilist_node.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -43,13 +43,13 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
const MDNode *TBAAInfo;
|
||||
public:
|
||||
PointerRec(Value *V)
|
||||
: Val(V), PrevInList(0), NextInList(0), AS(0), Size(0),
|
||||
: Val(V), PrevInList(nullptr), NextInList(nullptr), AS(nullptr), Size(0),
|
||||
TBAAInfo(DenseMapInfo<const MDNode *>::getEmptyKey()) {}
|
||||
|
||||
Value *getValue() const { return Val; }
|
||||
|
||||
PointerRec *getNext() const { return NextInList; }
|
||||
bool hasAliasSet() const { return AS != 0; }
|
||||
bool hasAliasSet() const { return AS != nullptr; }
|
||||
|
||||
PointerRec** setPrevInList(PointerRec **PIL) {
|
||||
PrevInList = PIL;
|
||||
@ -75,7 +75,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
// If we have missing or conflicting TBAAInfo, return null.
|
||||
if (TBAAInfo == DenseMapInfo<const MDNode *>::getEmptyKey() ||
|
||||
TBAAInfo == DenseMapInfo<const MDNode *>::getTombstoneKey())
|
||||
return 0;
|
||||
return nullptr;
|
||||
return TBAAInfo;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
}
|
||||
|
||||
void setAliasSet(AliasSet *as) {
|
||||
assert(AS == 0 && "Already have an alias set!");
|
||||
assert(!AS && "Already have an alias set!");
|
||||
AS = as;
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
*PrevInList = NextInList;
|
||||
if (AS->PtrListEnd == &NextInList) {
|
||||
AS->PtrListEnd = PrevInList;
|
||||
assert(*AS->PtrListEnd == 0 && "List not terminated right!");
|
||||
assert(*AS->PtrListEnd == nullptr && "List not terminated right!");
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
@ -174,7 +174,7 @@ public:
|
||||
class iterator;
|
||||
iterator begin() const { return iterator(PtrList); }
|
||||
iterator end() const { return iterator(); }
|
||||
bool empty() const { return PtrList == 0; }
|
||||
bool empty() const { return PtrList == nullptr; }
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
@ -184,7 +184,7 @@ public:
|
||||
PointerRec, ptrdiff_t> {
|
||||
PointerRec *CurNode;
|
||||
public:
|
||||
explicit iterator(PointerRec *CN = 0) : CurNode(CN) {}
|
||||
explicit iterator(PointerRec *CN = nullptr) : CurNode(CN) {}
|
||||
|
||||
bool operator==(const iterator& x) const {
|
||||
return CurNode == x.CurNode;
|
||||
@ -220,8 +220,9 @@ private:
|
||||
// Can only be created by AliasSetTracker. Also, ilist creates one
|
||||
// to serve as a sentinel.
|
||||
friend struct ilist_sentinel_traits<AliasSet>;
|
||||
AliasSet() : PtrList(0), PtrListEnd(&PtrList), Forward(0), RefCount(0),
|
||||
AccessTy(NoModRef), AliasTy(MustAlias), Volatile(false) {
|
||||
AliasSet()
|
||||
: PtrList(nullptr), PtrListEnd(&PtrList), Forward(nullptr), RefCount(0),
|
||||
AccessTy(NoModRef), AliasTy(MustAlias), Volatile(false) {
|
||||
}
|
||||
|
||||
AliasSet(const AliasSet &AS) LLVM_DELETED_FUNCTION;
|
||||
@ -282,10 +283,10 @@ class AliasSetTracker {
|
||||
/// notified whenever a Value is deleted.
|
||||
class ASTCallbackVH : public CallbackVH {
|
||||
AliasSetTracker *AST;
|
||||
virtual void deleted();
|
||||
virtual void allUsesReplacedWith(Value *);
|
||||
void deleted() override;
|
||||
void allUsesReplacedWith(Value *) override;
|
||||
public:
|
||||
ASTCallbackVH(Value *V, AliasSetTracker *AST = 0);
|
||||
ASTCallbackVH(Value *V, AliasSetTracker *AST = nullptr);
|
||||
ASTCallbackVH &operator=(Value *V);
|
||||
};
|
||||
/// ASTCallbackVHDenseMapInfo - Traits to tell DenseMap that tell us how to
|
||||
@ -354,7 +355,7 @@ public:
|
||||
/// pointer didn't alias anything).
|
||||
AliasSet &getAliasSetForPointer(Value *P, uint64_t Size,
|
||||
const MDNode *TBAAInfo,
|
||||
bool *New = 0);
|
||||
bool *New = nullptr);
|
||||
|
||||
/// getAliasSetForPointerIfExists - Return the alias set containing the
|
||||
/// location specified if one exists, otherwise return null.
|
||||
@ -408,7 +409,7 @@ private:
|
||||
// entry for the pointer if it doesn't already exist.
|
||||
AliasSet::PointerRec &getEntryFor(Value *V) {
|
||||
AliasSet::PointerRec *&Entry = PointerMap[ASTCallbackVH(V, this)];
|
||||
if (Entry == 0)
|
||||
if (!Entry)
|
||||
Entry = new AliasSet::PointerRec(V);
|
||||
return *Entry;
|
||||
}
|
||||
|
@ -1,347 +0,0 @@
|
||||
//===-- BlockFrequencyImpl.h - Block Frequency Implementation --*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Shared implementation of BlockFrequency for IR and Machine Instructions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_BLOCKFREQUENCYIMPL_H
|
||||
#define LLVM_ANALYSIS_BLOCKFREQUENCYIMPL_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/Support/BlockFrequency.h"
|
||||
#include "llvm/Support/BranchProbability.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
||||
class BlockFrequencyInfo;
|
||||
class MachineBlockFrequencyInfo;
|
||||
|
||||
/// BlockFrequencyImpl implements block frequency algorithm for IR and
|
||||
/// Machine Instructions. Algorithm starts with value ENTRY_FREQ
|
||||
/// for the entry block and then propagates frequencies using branch weights
|
||||
/// from (Machine)BranchProbabilityInfo. LoopInfo is not required because
|
||||
/// algorithm can find "backedges" by itself.
|
||||
template<class BlockT, class FunctionT, class BlockProbInfoT>
|
||||
class BlockFrequencyImpl {
|
||||
|
||||
DenseMap<const BlockT *, BlockFrequency> Freqs;
|
||||
|
||||
BlockProbInfoT *BPI;
|
||||
|
||||
FunctionT *Fn;
|
||||
|
||||
typedef GraphTraits< Inverse<BlockT *> > GT;
|
||||
|
||||
const uint32_t EntryFreq;
|
||||
|
||||
std::string getBlockName(BasicBlock *BB) const {
|
||||
return BB->getName().str();
|
||||
}
|
||||
|
||||
std::string getBlockName(MachineBasicBlock *MBB) const {
|
||||
std::string str;
|
||||
raw_string_ostream ss(str);
|
||||
ss << "BB#" << MBB->getNumber();
|
||||
|
||||
if (const BasicBlock *BB = MBB->getBasicBlock())
|
||||
ss << " derived from LLVM BB " << BB->getName();
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void setBlockFreq(BlockT *BB, BlockFrequency Freq) {
|
||||
Freqs[BB] = Freq;
|
||||
DEBUG(dbgs() << "Frequency(" << getBlockName(BB) << ") = " << Freq << "\n");
|
||||
}
|
||||
|
||||
/// getEdgeFreq - Return edge frequency based on SRC frequency and Src -> Dst
|
||||
/// edge probability.
|
||||
BlockFrequency getEdgeFreq(BlockT *Src, BlockT *Dst) const {
|
||||
BranchProbability Prob = BPI->getEdgeProbability(Src, Dst);
|
||||
return getBlockFreq(Src) * Prob;
|
||||
}
|
||||
|
||||
/// incBlockFreq - Increase BB block frequency by FREQ.
|
||||
///
|
||||
void incBlockFreq(BlockT *BB, BlockFrequency Freq) {
|
||||
Freqs[BB] += Freq;
|
||||
DEBUG(dbgs() << "Frequency(" << getBlockName(BB) << ") += " << Freq
|
||||
<< " --> " << Freqs[BB] << "\n");
|
||||
}
|
||||
|
||||
// All blocks in postorder.
|
||||
std::vector<BlockT *> POT;
|
||||
|
||||
// Map Block -> Position in reverse-postorder list.
|
||||
DenseMap<BlockT *, unsigned> RPO;
|
||||
|
||||
// For each loop header, record the per-iteration probability of exiting the
|
||||
// loop. This is the reciprocal of the expected number of loop iterations.
|
||||
typedef DenseMap<BlockT*, BranchProbability> LoopExitProbMap;
|
||||
LoopExitProbMap LoopExitProb;
|
||||
|
||||
// (reverse-)postorder traversal iterators.
|
||||
typedef typename std::vector<BlockT *>::iterator pot_iterator;
|
||||
typedef typename std::vector<BlockT *>::reverse_iterator rpot_iterator;
|
||||
|
||||
pot_iterator pot_begin() { return POT.begin(); }
|
||||
pot_iterator pot_end() { return POT.end(); }
|
||||
|
||||
rpot_iterator rpot_begin() { return POT.rbegin(); }
|
||||
rpot_iterator rpot_end() { return POT.rend(); }
|
||||
|
||||
rpot_iterator rpot_at(BlockT *BB) {
|
||||
rpot_iterator I = rpot_begin();
|
||||
unsigned idx = RPO.lookup(BB);
|
||||
assert(idx);
|
||||
std::advance(I, idx - 1);
|
||||
|
||||
assert(*I == BB);
|
||||
return I;
|
||||
}
|
||||
|
||||
/// isBackedge - Return if edge Src -> Dst is a reachable backedge.
|
||||
///
|
||||
bool isBackedge(BlockT *Src, BlockT *Dst) const {
|
||||
unsigned a = RPO.lookup(Src);
|
||||
if (!a)
|
||||
return false;
|
||||
unsigned b = RPO.lookup(Dst);
|
||||
assert(b && "Destination block should be reachable");
|
||||
return a >= b;
|
||||
}
|
||||
|
||||
/// getSingleBlockPred - return single BB block predecessor or NULL if
|
||||
/// BB has none or more predecessors.
|
||||
BlockT *getSingleBlockPred(BlockT *BB) {
|
||||
typename GT::ChildIteratorType
|
||||
PI = GraphTraits< Inverse<BlockT *> >::child_begin(BB),
|
||||
PE = GraphTraits< Inverse<BlockT *> >::child_end(BB);
|
||||
|
||||
if (PI == PE)
|
||||
return 0;
|
||||
|
||||
BlockT *Pred = *PI;
|
||||
|
||||
++PI;
|
||||
if (PI != PE)
|
||||
return 0;
|
||||
|
||||
return Pred;
|
||||
}
|
||||
|
||||
void doBlock(BlockT *BB, BlockT *LoopHead,
|
||||
SmallPtrSet<BlockT *, 8> &BlocksInLoop) {
|
||||
|
||||
DEBUG(dbgs() << "doBlock(" << getBlockName(BB) << ")\n");
|
||||
setBlockFreq(BB, 0);
|
||||
|
||||
if (BB == LoopHead) {
|
||||
setBlockFreq(BB, EntryFreq);
|
||||
return;
|
||||
}
|
||||
|
||||
if(BlockT *Pred = getSingleBlockPred(BB)) {
|
||||
if (BlocksInLoop.count(Pred))
|
||||
setBlockFreq(BB, getEdgeFreq(Pred, BB));
|
||||
// TODO: else? irreducible, ignore it for now.
|
||||
return;
|
||||
}
|
||||
|
||||
bool isInLoop = false;
|
||||
bool isLoopHead = false;
|
||||
|
||||
for (typename GT::ChildIteratorType
|
||||
PI = GraphTraits< Inverse<BlockT *> >::child_begin(BB),
|
||||
PE = GraphTraits< Inverse<BlockT *> >::child_end(BB);
|
||||
PI != PE; ++PI) {
|
||||
BlockT *Pred = *PI;
|
||||
|
||||
if (isBackedge(Pred, BB)) {
|
||||
isLoopHead = true;
|
||||
} else if (BlocksInLoop.count(Pred)) {
|
||||
incBlockFreq(BB, getEdgeFreq(Pred, BB));
|
||||
isInLoop = true;
|
||||
}
|
||||
// TODO: else? irreducible.
|
||||
}
|
||||
|
||||
if (!isInLoop)
|
||||
return;
|
||||
|
||||
if (!isLoopHead)
|
||||
return;
|
||||
|
||||
// This block is a loop header, so boost its frequency by the expected
|
||||
// number of loop iterations. The loop blocks will be revisited so they all
|
||||
// get this boost.
|
||||
typename LoopExitProbMap::const_iterator I = LoopExitProb.find(BB);
|
||||
assert(I != LoopExitProb.end() && "Loop header missing from table");
|
||||
Freqs[BB] /= I->second;
|
||||
DEBUG(dbgs() << "Loop header scaled to " << Freqs[BB] << ".\n");
|
||||
}
|
||||
|
||||
/// doLoop - Propagate block frequency down through the loop.
|
||||
void doLoop(BlockT *Head, BlockT *Tail) {
|
||||
DEBUG(dbgs() << "doLoop(" << getBlockName(Head) << ", "
|
||||
<< getBlockName(Tail) << ")\n");
|
||||
|
||||
SmallPtrSet<BlockT *, 8> BlocksInLoop;
|
||||
|
||||
for (rpot_iterator I = rpot_at(Head), E = rpot_at(Tail); ; ++I) {
|
||||
BlockT *BB = *I;
|
||||
doBlock(BB, Head, BlocksInLoop);
|
||||
|
||||
BlocksInLoop.insert(BB);
|
||||
if (I == E)
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute loop's cyclic probability using backedges probabilities.
|
||||
BlockFrequency BackFreq;
|
||||
for (typename GT::ChildIteratorType
|
||||
PI = GraphTraits< Inverse<BlockT *> >::child_begin(Head),
|
||||
PE = GraphTraits< Inverse<BlockT *> >::child_end(Head);
|
||||
PI != PE; ++PI) {
|
||||
BlockT *Pred = *PI;
|
||||
assert(Pred);
|
||||
if (isBackedge(Pred, Head))
|
||||
BackFreq += getEdgeFreq(Pred, Head);
|
||||
}
|
||||
|
||||
// The cyclic probability is freq(BackEdges) / freq(Head), where freq(Head)
|
||||
// only counts edges entering the loop, not the loop backedges.
|
||||
// The probability of leaving the loop on each iteration is:
|
||||
//
|
||||
// ExitProb = 1 - CyclicProb
|
||||
//
|
||||
// The Expected number of loop iterations is:
|
||||
//
|
||||
// Iterations = 1 / ExitProb
|
||||
//
|
||||
uint64_t D = std::max(getBlockFreq(Head).getFrequency(), UINT64_C(1));
|
||||
uint64_t N = std::max(BackFreq.getFrequency(), UINT64_C(1));
|
||||
if (N < D)
|
||||
N = D - N;
|
||||
else
|
||||
// We'd expect N < D, but rounding and saturation means that can't be
|
||||
// guaranteed.
|
||||
N = 1;
|
||||
|
||||
// Now ExitProb = N / D, make sure it fits in an i32/i32 fraction.
|
||||
assert(N <= D);
|
||||
if (D > UINT32_MAX) {
|
||||
unsigned Shift = 32 - countLeadingZeros(D);
|
||||
D >>= Shift;
|
||||
N >>= Shift;
|
||||
if (N == 0)
|
||||
N = 1;
|
||||
}
|
||||
BranchProbability LEP = BranchProbability(N, D);
|
||||
LoopExitProb.insert(std::make_pair(Head, LEP));
|
||||
DEBUG(dbgs() << "LoopExitProb[" << getBlockName(Head) << "] = " << LEP
|
||||
<< " from 1 - " << BackFreq << " / " << getBlockFreq(Head)
|
||||
<< ".\n");
|
||||
}
|
||||
|
||||
friend class BlockFrequencyInfo;
|
||||
friend class MachineBlockFrequencyInfo;
|
||||
|
||||
BlockFrequencyImpl() : EntryFreq(BlockFrequency::getEntryFrequency()) { }
|
||||
|
||||
void doFunction(FunctionT *fn, BlockProbInfoT *bpi) {
|
||||
Fn = fn;
|
||||
BPI = bpi;
|
||||
|
||||
// Clear everything.
|
||||
RPO.clear();
|
||||
POT.clear();
|
||||
LoopExitProb.clear();
|
||||
Freqs.clear();
|
||||
|
||||
BlockT *EntryBlock = fn->begin();
|
||||
|
||||
std::copy(po_begin(EntryBlock), po_end(EntryBlock), std::back_inserter(POT));
|
||||
|
||||
unsigned RPOidx = 0;
|
||||
for (rpot_iterator I = rpot_begin(), E = rpot_end(); I != E; ++I) {
|
||||
BlockT *BB = *I;
|
||||
RPO[BB] = ++RPOidx;
|
||||
DEBUG(dbgs() << "RPO[" << getBlockName(BB) << "] = " << RPO[BB] << "\n");
|
||||
}
|
||||
|
||||
// Travel over all blocks in postorder.
|
||||
for (pot_iterator I = pot_begin(), E = pot_end(); I != E; ++I) {
|
||||
BlockT *BB = *I;
|
||||
BlockT *LastTail = 0;
|
||||
DEBUG(dbgs() << "POT: " << getBlockName(BB) << "\n");
|
||||
|
||||
for (typename GT::ChildIteratorType
|
||||
PI = GraphTraits< Inverse<BlockT *> >::child_begin(BB),
|
||||
PE = GraphTraits< Inverse<BlockT *> >::child_end(BB);
|
||||
PI != PE; ++PI) {
|
||||
|
||||
BlockT *Pred = *PI;
|
||||
if (isBackedge(Pred, BB) && (!LastTail || RPO[Pred] > RPO[LastTail]))
|
||||
LastTail = Pred;
|
||||
}
|
||||
|
||||
if (LastTail)
|
||||
doLoop(BB, LastTail);
|
||||
}
|
||||
|
||||
// At the end assume the whole function as a loop, and travel over it once
|
||||
// again.
|
||||
doLoop(*(rpot_begin()), *(pot_begin()));
|
||||
}
|
||||
|
||||
public:
|
||||
/// getBlockFreq - Return block frequency. Return 0 if we don't have it.
|
||||
BlockFrequency getBlockFreq(const BlockT *BB) const {
|
||||
typename DenseMap<const BlockT *, BlockFrequency>::const_iterator
|
||||
I = Freqs.find(BB);
|
||||
if (I != Freqs.end())
|
||||
return I->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const {
|
||||
OS << "\n\n---- Block Freqs ----\n";
|
||||
for (typename FunctionT::iterator I = Fn->begin(), E = Fn->end(); I != E;) {
|
||||
BlockT *BB = I++;
|
||||
OS << " " << getBlockName(BB) << " = " << getBlockFreq(BB) << "\n";
|
||||
|
||||
for (typename GraphTraits<BlockT *>::ChildIteratorType
|
||||
SI = GraphTraits<BlockT *>::child_begin(BB),
|
||||
SE = GraphTraits<BlockT *>::child_end(BB); SI != SE; ++SI) {
|
||||
BlockT *Succ = *SI;
|
||||
OS << " " << getBlockName(BB) << " -> " << getBlockName(Succ)
|
||||
<< " = " << getEdgeFreq(BB, Succ) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump() const {
|
||||
print(dbgs());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===------- BlockFrequencyInfo.h - Block Frequency Analysis --*- C++ -*---===//
|
||||
//===- BlockFrequencyInfo.h - Block Frequency Analysis ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -21,14 +21,13 @@
|
||||
namespace llvm {
|
||||
|
||||
class BranchProbabilityInfo;
|
||||
template<class BlockT, class FunctionT, class BranchProbInfoT>
|
||||
class BlockFrequencyImpl;
|
||||
template <class BlockT> class BlockFrequencyInfoImpl;
|
||||
|
||||
/// BlockFrequencyInfo pass uses BlockFrequencyImpl implementation to estimate
|
||||
/// IR basic block frequencies.
|
||||
/// BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to
|
||||
/// estimate IR basic block frequencies.
|
||||
class BlockFrequencyInfo : public FunctionPass {
|
||||
|
||||
BlockFrequencyImpl<BasicBlock, Function, BranchProbabilityInfo> *BFI;
|
||||
typedef BlockFrequencyInfoImpl<BasicBlock> ImplType;
|
||||
std::unique_ptr<ImplType> BFI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
@ -37,10 +36,11 @@ public:
|
||||
|
||||
~BlockFrequencyInfo();
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnFunction(Function &F);
|
||||
void print(raw_ostream &O, const Module *M) const;
|
||||
bool runOnFunction(Function &F) override;
|
||||
void releaseMemory() override;
|
||||
void print(raw_ostream &O, const Module *M) const override;
|
||||
const Function *getFunction() const;
|
||||
void view() const;
|
||||
|
||||
@ -50,6 +50,17 @@ public:
|
||||
/// comparison to the other block frequencies. We do this to avoid using of
|
||||
/// floating points.
|
||||
BlockFrequency getBlockFreq(const BasicBlock *BB) const;
|
||||
|
||||
// Print the block frequency Freq to OS using the current functions entry
|
||||
// frequency to convert freq into a relative decimal form.
|
||||
raw_ostream &printBlockFreq(raw_ostream &OS, const BlockFrequency Freq) const;
|
||||
|
||||
// Convenience method that attempts to look up the frequency associated with
|
||||
// BB and print it to OS.
|
||||
raw_ostream &printBlockFreq(raw_ostream &OS, const BasicBlock *BB) const;
|
||||
|
||||
uint64_t getEntryFreq() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
1181
contrib/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
Normal file
1181
contrib/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/BranchProbability.h"
|
||||
@ -44,9 +45,9 @@ public:
|
||||
initializeBranchProbabilityInfoPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
bool runOnFunction(Function &F);
|
||||
void print(raw_ostream &OS, const Module *M = 0) const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
void print(raw_ostream &OS, const Module *M = nullptr) const override;
|
||||
|
||||
/// \brief Get an edge's probability, relative to other out-edges of the Src.
|
||||
///
|
||||
@ -98,6 +99,9 @@ public:
|
||||
/// It is guaranteed to fall between 1 and UINT32_MAX.
|
||||
uint32_t getEdgeWeight(const BasicBlock *Src, const BasicBlock *Dst) const;
|
||||
|
||||
uint32_t getEdgeWeight(const BasicBlock *Src,
|
||||
succ_const_iterator Dst) const;
|
||||
|
||||
/// \brief Set the raw edge weight for a given edge.
|
||||
///
|
||||
/// This allows a pass to explicitly set the edge weight for an edge. It can
|
||||
|
@ -16,7 +16,7 @@
|
||||
#define LLVM_ANALYSIS_CFG_H
|
||||
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -65,8 +65,8 @@ bool isCriticalEdge(const TerminatorInst *TI, unsigned SuccNum,
|
||||
/// on branchy code but not loops, and LI is most useful on code with loops but
|
||||
/// does not help on branchy code outside loops.
|
||||
bool isPotentiallyReachable(const Instruction *From, const Instruction *To,
|
||||
const DominatorTree *DT = 0,
|
||||
const LoopInfo *LI = 0);
|
||||
const DominatorTree *DT = nullptr,
|
||||
const LoopInfo *LI = nullptr);
|
||||
|
||||
/// \brief Determine whether block 'To' is reachable from 'From', returning
|
||||
/// true if uncertain.
|
||||
@ -75,8 +75,8 @@ bool isPotentiallyReachable(const Instruction *From, const Instruction *To,
|
||||
/// Returns false only if we can prove that once 'From' has been reached then
|
||||
/// 'To' can not be executed. Conservatively returns true.
|
||||
bool isPotentiallyReachable(const BasicBlock *From, const BasicBlock *To,
|
||||
const DominatorTree *DT = 0,
|
||||
const LoopInfo *LI = 0);
|
||||
const DominatorTree *DT = nullptr,
|
||||
const LoopInfo *LI = nullptr);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -15,11 +15,10 @@
|
||||
#ifndef LLVM_ANALYSIS_CFGPRINTER_H
|
||||
#define LLVM_ANALYSIS_CFGPRINTER_H
|
||||
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -40,7 +39,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
|
||||
WriteAsOperand(OS, Node, false);
|
||||
Node->printAsOperand(OS, false);
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
@ -51,7 +50,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
||||
raw_string_ostream OS(Str);
|
||||
|
||||
if (Node->getName().empty()) {
|
||||
WriteAsOperand(OS, Node, false);
|
||||
Node->printAsOperand(OS, false);
|
||||
OS << ":";
|
||||
}
|
||||
|
||||
|
591
contrib/llvm/include/llvm/Analysis/CGSCCPassManager.h
Normal file
591
contrib/llvm/include/llvm/Analysis/CGSCCPassManager.h
Normal file
@ -0,0 +1,591 @@
|
||||
//===- CGSCCPassManager.h - Call graph pass management ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This header provides classes for managing passes over SCCs of the call
|
||||
/// graph. These passes form an important component of LLVM's interprocedural
|
||||
/// optimizations. Because they operate on the SCCs of the call graph, and they
|
||||
/// wtraverse the graph in post order, they can effectively do pair-wise
|
||||
/// interprocedural optimizations for all call edges in the program. At each
|
||||
/// call site edge, the callee has already been optimized as much as is
|
||||
/// possible. This in turn allows very accurate analysis of it for IPO.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CGSCC_PASS_MANAGER_H
|
||||
#define LLVM_ANALYSIS_CGSCC_PASS_MANAGER_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Analysis/LazyCallGraph.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CGSCCAnalysisManager;
|
||||
|
||||
class CGSCCPassManager {
|
||||
public:
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
CGSCCPassManager() {}
|
||||
CGSCCPassManager(CGSCCPassManager &&Arg) : Passes(std::move(Arg.Passes)) {}
|
||||
CGSCCPassManager &operator=(CGSCCPassManager &&RHS) {
|
||||
Passes = std::move(RHS.Passes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Run all of the CGSCC passes in this pass manager over a SCC.
|
||||
PreservedAnalyses run(LazyCallGraph::SCC *C,
|
||||
CGSCCAnalysisManager *AM = nullptr);
|
||||
|
||||
template <typename CGSCCPassT> void addPass(CGSCCPassT Pass) {
|
||||
Passes.emplace_back(new CGSCCPassModel<CGSCCPassT>(std::move(Pass)));
|
||||
}
|
||||
|
||||
static StringRef name() { return "CGSCCPassManager"; }
|
||||
|
||||
private:
|
||||
// Pull in the concept type and model template specialized for SCCs.
|
||||
typedef detail::PassConcept<LazyCallGraph::SCC *, CGSCCAnalysisManager>
|
||||
CGSCCPassConcept;
|
||||
template <typename PassT>
|
||||
struct CGSCCPassModel
|
||||
: detail::PassModel<LazyCallGraph::SCC *, CGSCCAnalysisManager, PassT> {
|
||||
CGSCCPassModel(PassT Pass)
|
||||
: detail::PassModel<LazyCallGraph::SCC *, CGSCCAnalysisManager, PassT>(
|
||||
std::move(Pass)) {}
|
||||
};
|
||||
|
||||
CGSCCPassManager(const CGSCCPassManager &) LLVM_DELETED_FUNCTION;
|
||||
CGSCCPassManager &operator=(const CGSCCPassManager &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
std::vector<std::unique_ptr<CGSCCPassConcept>> Passes;
|
||||
};
|
||||
|
||||
/// \brief A function analysis manager to coordinate and cache analyses run over
|
||||
/// a module.
|
||||
class CGSCCAnalysisManager : public detail::AnalysisManagerBase<
|
||||
CGSCCAnalysisManager, LazyCallGraph::SCC *> {
|
||||
friend class detail::AnalysisManagerBase<CGSCCAnalysisManager,
|
||||
LazyCallGraph::SCC *>;
|
||||
typedef detail::AnalysisManagerBase<CGSCCAnalysisManager,
|
||||
LazyCallGraph::SCC *> BaseT;
|
||||
typedef BaseT::ResultConceptT ResultConceptT;
|
||||
typedef BaseT::PassConceptT PassConceptT;
|
||||
|
||||
public:
|
||||
// Most public APIs are inherited from the CRTP base class.
|
||||
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
CGSCCAnalysisManager() {}
|
||||
CGSCCAnalysisManager(CGSCCAnalysisManager &&Arg)
|
||||
: BaseT(std::move(static_cast<BaseT &>(Arg))),
|
||||
CGSCCAnalysisResults(std::move(Arg.CGSCCAnalysisResults)) {}
|
||||
CGSCCAnalysisManager &operator=(CGSCCAnalysisManager &&RHS) {
|
||||
BaseT::operator=(std::move(static_cast<BaseT &>(RHS)));
|
||||
CGSCCAnalysisResults = std::move(RHS.CGSCCAnalysisResults);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the analysis manager has an empty results cache.
|
||||
bool empty() const;
|
||||
|
||||
/// \brief Clear the function analysis result cache.
|
||||
///
|
||||
/// This routine allows cleaning up when the set of functions itself has
|
||||
/// potentially changed, and thus we can't even look up a a result and
|
||||
/// invalidate it directly. Notably, this does *not* call invalidate
|
||||
/// functions as there is nothing to be done for them.
|
||||
void clear();
|
||||
|
||||
private:
|
||||
CGSCCAnalysisManager(const CGSCCAnalysisManager &) LLVM_DELETED_FUNCTION;
|
||||
CGSCCAnalysisManager &
|
||||
operator=(const CGSCCAnalysisManager &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
/// \brief Get a function pass result, running the pass if necessary.
|
||||
ResultConceptT &getResultImpl(void *PassID, LazyCallGraph::SCC *C);
|
||||
|
||||
/// \brief Get a cached function pass result or return null.
|
||||
ResultConceptT *getCachedResultImpl(void *PassID,
|
||||
LazyCallGraph::SCC *C) const;
|
||||
|
||||
/// \brief Invalidate a function pass result.
|
||||
void invalidateImpl(void *PassID, LazyCallGraph::SCC *C);
|
||||
|
||||
/// \brief Invalidate the results for a function..
|
||||
void invalidateImpl(LazyCallGraph::SCC *C, const PreservedAnalyses &PA);
|
||||
|
||||
/// \brief List of function analysis pass IDs and associated concept pointers.
|
||||
///
|
||||
/// Requires iterators to be valid across appending new entries and arbitrary
|
||||
/// erases. Provides both the pass ID and concept pointer such that it is
|
||||
/// half of a bijection and provides storage for the actual result concept.
|
||||
typedef std::list<
|
||||
std::pair<void *, std::unique_ptr<detail::AnalysisResultConcept<
|
||||
LazyCallGraph::SCC *>>>> CGSCCAnalysisResultListT;
|
||||
|
||||
/// \brief Map type from function pointer to our custom list type.
|
||||
typedef DenseMap<LazyCallGraph::SCC *, CGSCCAnalysisResultListT>
|
||||
CGSCCAnalysisResultListMapT;
|
||||
|
||||
/// \brief Map from function to a list of function analysis results.
|
||||
///
|
||||
/// Provides linear time removal of all analysis results for a function and
|
||||
/// the ultimate storage for a particular cached analysis result.
|
||||
CGSCCAnalysisResultListMapT CGSCCAnalysisResultLists;
|
||||
|
||||
/// \brief Map type from a pair of analysis ID and function pointer to an
|
||||
/// iterator into a particular result list.
|
||||
typedef DenseMap<std::pair<void *, LazyCallGraph::SCC *>,
|
||||
CGSCCAnalysisResultListT::iterator> CGSCCAnalysisResultMapT;
|
||||
|
||||
/// \brief Map from an analysis ID and function to a particular cached
|
||||
/// analysis result.
|
||||
CGSCCAnalysisResultMapT CGSCCAnalysisResults;
|
||||
};
|
||||
|
||||
/// \brief A module analysis which acts as a proxy for a CGSCC analysis
|
||||
/// manager.
|
||||
///
|
||||
/// This primarily proxies invalidation information from the module analysis
|
||||
/// manager and module pass manager to a CGSCC analysis manager. You should
|
||||
/// never use a CGSCC analysis manager from within (transitively) a module
|
||||
/// pass manager unless your parent module pass has received a proxy result
|
||||
/// object for it.
|
||||
class CGSCCAnalysisManagerModuleProxy {
|
||||
public:
|
||||
class Result {
|
||||
public:
|
||||
explicit Result(CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {}
|
||||
// We have to explicitly define all the special member functions because
|
||||
// MSVC refuses to generate them.
|
||||
Result(const Result &Arg) : CGAM(Arg.CGAM) {}
|
||||
Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {}
|
||||
Result &operator=(Result RHS) {
|
||||
std::swap(CGAM, RHS.CGAM);
|
||||
return *this;
|
||||
}
|
||||
~Result();
|
||||
|
||||
/// \brief Accessor for the \c CGSCCAnalysisManager.
|
||||
CGSCCAnalysisManager &getManager() { return *CGAM; }
|
||||
|
||||
/// \brief Handler for invalidation of the module.
|
||||
///
|
||||
/// If this analysis itself is preserved, then we assume that the call
|
||||
/// graph of the module hasn't changed and thus we don't need to invalidate
|
||||
/// *all* cached data associated with a \c SCC* in the \c
|
||||
/// CGSCCAnalysisManager.
|
||||
///
|
||||
/// Regardless of whether this analysis is marked as preserved, all of the
|
||||
/// analyses in the \c CGSCCAnalysisManager are potentially invalidated
|
||||
/// based on the set of preserved analyses.
|
||||
bool invalidate(Module *M, const PreservedAnalyses &PA);
|
||||
|
||||
private:
|
||||
CGSCCAnalysisManager *CGAM;
|
||||
};
|
||||
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
explicit CGSCCAnalysisManagerModuleProxy(CGSCCAnalysisManager &CGAM)
|
||||
: CGAM(&CGAM) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
CGSCCAnalysisManagerModuleProxy(
|
||||
const CGSCCAnalysisManagerModuleProxy &Arg)
|
||||
: CGAM(Arg.CGAM) {}
|
||||
CGSCCAnalysisManagerModuleProxy(CGSCCAnalysisManagerModuleProxy &&Arg)
|
||||
: CGAM(std::move(Arg.CGAM)) {}
|
||||
CGSCCAnalysisManagerModuleProxy &
|
||||
operator=(CGSCCAnalysisManagerModuleProxy RHS) {
|
||||
std::swap(CGAM, RHS.CGAM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Run the analysis pass and create our proxy result object.
|
||||
///
|
||||
/// This doesn't do any interesting work, it is primarily used to insert our
|
||||
/// proxy result object into the module analysis cache so that we can proxy
|
||||
/// invalidation to the CGSCC analysis manager.
|
||||
///
|
||||
/// In debug builds, it will also assert that the analysis manager is empty
|
||||
/// as no queries should arrive at the CGSCC analysis manager prior to
|
||||
/// this analysis being requested.
|
||||
Result run(Module *M);
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
|
||||
CGSCCAnalysisManager *CGAM;
|
||||
};
|
||||
|
||||
/// \brief A CGSCC analysis which acts as a proxy for a module analysis
|
||||
/// manager.
|
||||
///
|
||||
/// This primarily provides an accessor to a parent module analysis manager to
|
||||
/// CGSCC passes. Only the const interface of the module analysis manager is
|
||||
/// provided to indicate that once inside of a CGSCC analysis pass you
|
||||
/// cannot request a module analysis to actually run. Instead, the user must
|
||||
/// rely on the \c getCachedResult API.
|
||||
///
|
||||
/// This proxy *doesn't* manage the invalidation in any way. That is handled by
|
||||
/// the recursive return path of each layer of the pass manager and the
|
||||
/// returned PreservedAnalysis set.
|
||||
class ModuleAnalysisManagerCGSCCProxy {
|
||||
public:
|
||||
/// \brief Result proxy object for \c ModuleAnalysisManagerCGSCCProxy.
|
||||
class Result {
|
||||
public:
|
||||
explicit Result(const ModuleAnalysisManager &MAM) : MAM(&MAM) {}
|
||||
// We have to explicitly define all the special member functions because
|
||||
// MSVC refuses to generate them.
|
||||
Result(const Result &Arg) : MAM(Arg.MAM) {}
|
||||
Result(Result &&Arg) : MAM(std::move(Arg.MAM)) {}
|
||||
Result &operator=(Result RHS) {
|
||||
std::swap(MAM, RHS.MAM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const ModuleAnalysisManager &getManager() const { return *MAM; }
|
||||
|
||||
/// \brief Handle invalidation by ignoring it, this pass is immutable.
|
||||
bool invalidate(LazyCallGraph::SCC *) { return false; }
|
||||
|
||||
private:
|
||||
const ModuleAnalysisManager *MAM;
|
||||
};
|
||||
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
ModuleAnalysisManagerCGSCCProxy(const ModuleAnalysisManager &MAM)
|
||||
: MAM(&MAM) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
ModuleAnalysisManagerCGSCCProxy(
|
||||
const ModuleAnalysisManagerCGSCCProxy &Arg)
|
||||
: MAM(Arg.MAM) {}
|
||||
ModuleAnalysisManagerCGSCCProxy(ModuleAnalysisManagerCGSCCProxy &&Arg)
|
||||
: MAM(std::move(Arg.MAM)) {}
|
||||
ModuleAnalysisManagerCGSCCProxy &
|
||||
operator=(ModuleAnalysisManagerCGSCCProxy RHS) {
|
||||
std::swap(MAM, RHS.MAM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Run the analysis pass and create our proxy result object.
|
||||
/// Nothing to see here, it just forwards the \c MAM reference into the
|
||||
/// result.
|
||||
Result run(LazyCallGraph::SCC *) { return Result(*MAM); }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
|
||||
const ModuleAnalysisManager *MAM;
|
||||
};
|
||||
|
||||
/// \brief The core module pass which does a post-order walk of the SCCs and
|
||||
/// runs a CGSCC pass over each one.
|
||||
///
|
||||
/// Designed to allow composition of a CGSCCPass(Manager) and
|
||||
/// a ModulePassManager. Note that this pass must be run with a module analysis
|
||||
/// manager as it uses the LazyCallGraph analysis. It will also run the
|
||||
/// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC
|
||||
/// pass over the module to enable a \c FunctionAnalysisManager to be used
|
||||
/// within this run safely.
|
||||
template <typename CGSCCPassT> class ModuleToPostOrderCGSCCPassAdaptor {
|
||||
public:
|
||||
explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass)
|
||||
: Pass(std::move(Pass)) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
ModuleToPostOrderCGSCCPassAdaptor(
|
||||
const ModuleToPostOrderCGSCCPassAdaptor &Arg)
|
||||
: Pass(Arg.Pass) {}
|
||||
ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg)
|
||||
: Pass(std::move(Arg.Pass)) {}
|
||||
friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS,
|
||||
ModuleToPostOrderCGSCCPassAdaptor &RHS) {
|
||||
using std::swap;
|
||||
swap(LHS.Pass, RHS.Pass);
|
||||
}
|
||||
ModuleToPostOrderCGSCCPassAdaptor &
|
||||
operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) {
|
||||
swap(*this, RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Runs the CGSCC pass across every SCC in the module.
|
||||
PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) {
|
||||
assert(AM && "We need analyses to compute the call graph!");
|
||||
|
||||
// Setup the CGSCC analysis manager from its proxy.
|
||||
CGSCCAnalysisManager &CGAM =
|
||||
AM->getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager();
|
||||
|
||||
// Get the call graph for this module.
|
||||
LazyCallGraph &CG = AM->getResult<LazyCallGraphAnalysis>(M);
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
for (LazyCallGraph::SCC &C : CG.postorder_sccs()) {
|
||||
PreservedAnalyses PassPA = Pass.run(&C, &CGAM);
|
||||
|
||||
// We know that the CGSCC pass couldn't have invalidated any other
|
||||
// SCC's analyses (that's the contract of a CGSCC pass), so
|
||||
// directly handle the CGSCC analysis manager's invalidation here.
|
||||
// FIXME: This isn't quite correct. We need to handle the case where the
|
||||
// pass updated the CG, particularly some child of the current SCC, and
|
||||
// invalidate its analyses.
|
||||
CGAM.invalidate(&C, PassPA);
|
||||
|
||||
// Then intersect the preserved set so that invalidation of module
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
PA.intersect(std::move(PassPA));
|
||||
}
|
||||
|
||||
// By definition we preserve the proxy. This precludes *any* invalidation
|
||||
// of CGSCC analyses by the proxy, but that's OK because we've taken
|
||||
// care to invalidate analyses in the CGSCC analysis manager
|
||||
// incrementally above.
|
||||
PA.preserve<CGSCCAnalysisManagerModuleProxy>();
|
||||
return PA;
|
||||
}
|
||||
|
||||
static StringRef name() { return "ModuleToPostOrderCGSCCPassAdaptor"; }
|
||||
|
||||
private:
|
||||
CGSCCPassT Pass;
|
||||
};
|
||||
|
||||
/// \brief A function to deduce a function pass type and wrap it in the
|
||||
/// templated adaptor.
|
||||
template <typename CGSCCPassT>
|
||||
ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>
|
||||
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) {
|
||||
return std::move(
|
||||
ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass)));
|
||||
}
|
||||
|
||||
/// \brief A CGSCC analysis which acts as a proxy for a function analysis
|
||||
/// manager.
|
||||
///
|
||||
/// This primarily proxies invalidation information from the CGSCC analysis
|
||||
/// manager and CGSCC pass manager to a function analysis manager. You should
|
||||
/// never use a function analysis manager from within (transitively) a CGSCC
|
||||
/// pass manager unless your parent CGSCC pass has received a proxy result
|
||||
/// object for it.
|
||||
class FunctionAnalysisManagerCGSCCProxy {
|
||||
public:
|
||||
class Result {
|
||||
public:
|
||||
explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
|
||||
// We have to explicitly define all the special member functions because
|
||||
// MSVC refuses to generate them.
|
||||
Result(const Result &Arg) : FAM(Arg.FAM) {}
|
||||
Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {}
|
||||
Result &operator=(Result RHS) {
|
||||
std::swap(FAM, RHS.FAM);
|
||||
return *this;
|
||||
}
|
||||
~Result();
|
||||
|
||||
/// \brief Accessor for the \c FunctionAnalysisManager.
|
||||
FunctionAnalysisManager &getManager() { return *FAM; }
|
||||
|
||||
/// \brief Handler for invalidation of the SCC.
|
||||
///
|
||||
/// If this analysis itself is preserved, then we assume that the set of \c
|
||||
/// Function objects in the \c SCC hasn't changed and thus we don't need
|
||||
/// to invalidate *all* cached data associated with a \c Function* in the \c
|
||||
/// FunctionAnalysisManager.
|
||||
///
|
||||
/// Regardless of whether this analysis is marked as preserved, all of the
|
||||
/// analyses in the \c FunctionAnalysisManager are potentially invalidated
|
||||
/// based on the set of preserved analyses.
|
||||
bool invalidate(LazyCallGraph::SCC *C, const PreservedAnalyses &PA);
|
||||
|
||||
private:
|
||||
FunctionAnalysisManager *FAM;
|
||||
};
|
||||
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
explicit FunctionAnalysisManagerCGSCCProxy(FunctionAnalysisManager &FAM)
|
||||
: FAM(&FAM) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
FunctionAnalysisManagerCGSCCProxy(
|
||||
const FunctionAnalysisManagerCGSCCProxy &Arg)
|
||||
: FAM(Arg.FAM) {}
|
||||
FunctionAnalysisManagerCGSCCProxy(FunctionAnalysisManagerCGSCCProxy &&Arg)
|
||||
: FAM(std::move(Arg.FAM)) {}
|
||||
FunctionAnalysisManagerCGSCCProxy &
|
||||
operator=(FunctionAnalysisManagerCGSCCProxy RHS) {
|
||||
std::swap(FAM, RHS.FAM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Run the analysis pass and create our proxy result object.
|
||||
///
|
||||
/// This doesn't do any interesting work, it is primarily used to insert our
|
||||
/// proxy result object into the module analysis cache so that we can proxy
|
||||
/// invalidation to the function analysis manager.
|
||||
///
|
||||
/// In debug builds, it will also assert that the analysis manager is empty
|
||||
/// as no queries should arrive at the function analysis manager prior to
|
||||
/// this analysis being requested.
|
||||
Result run(LazyCallGraph::SCC *C);
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
|
||||
FunctionAnalysisManager *FAM;
|
||||
};
|
||||
|
||||
/// \brief A function analysis which acts as a proxy for a CGSCC analysis
|
||||
/// manager.
|
||||
///
|
||||
/// This primarily provides an accessor to a parent CGSCC analysis manager to
|
||||
/// function passes. Only the const interface of the CGSCC analysis manager is
|
||||
/// provided to indicate that once inside of a function analysis pass you
|
||||
/// cannot request a CGSCC analysis to actually run. Instead, the user must
|
||||
/// rely on the \c getCachedResult API.
|
||||
///
|
||||
/// This proxy *doesn't* manage the invalidation in any way. That is handled by
|
||||
/// the recursive return path of each layer of the pass manager and the
|
||||
/// returned PreservedAnalysis set.
|
||||
class CGSCCAnalysisManagerFunctionProxy {
|
||||
public:
|
||||
/// \brief Result proxy object for \c ModuleAnalysisManagerFunctionProxy.
|
||||
class Result {
|
||||
public:
|
||||
explicit Result(const CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {}
|
||||
// We have to explicitly define all the special member functions because
|
||||
// MSVC refuses to generate them.
|
||||
Result(const Result &Arg) : CGAM(Arg.CGAM) {}
|
||||
Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {}
|
||||
Result &operator=(Result RHS) {
|
||||
std::swap(CGAM, RHS.CGAM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CGSCCAnalysisManager &getManager() const { return *CGAM; }
|
||||
|
||||
/// \brief Handle invalidation by ignoring it, this pass is immutable.
|
||||
bool invalidate(Function *) { return false; }
|
||||
|
||||
private:
|
||||
const CGSCCAnalysisManager *CGAM;
|
||||
};
|
||||
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
CGSCCAnalysisManagerFunctionProxy(const CGSCCAnalysisManager &CGAM)
|
||||
: CGAM(&CGAM) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
CGSCCAnalysisManagerFunctionProxy(
|
||||
const CGSCCAnalysisManagerFunctionProxy &Arg)
|
||||
: CGAM(Arg.CGAM) {}
|
||||
CGSCCAnalysisManagerFunctionProxy(CGSCCAnalysisManagerFunctionProxy &&Arg)
|
||||
: CGAM(std::move(Arg.CGAM)) {}
|
||||
CGSCCAnalysisManagerFunctionProxy &
|
||||
operator=(CGSCCAnalysisManagerFunctionProxy RHS) {
|
||||
std::swap(CGAM, RHS.CGAM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Run the analysis pass and create our proxy result object.
|
||||
/// Nothing to see here, it just forwards the \c CGAM reference into the
|
||||
/// result.
|
||||
Result run(Function *) { return Result(*CGAM); }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
|
||||
const CGSCCAnalysisManager *CGAM;
|
||||
};
|
||||
|
||||
/// \brief Adaptor that maps from a SCC to its functions.
|
||||
///
|
||||
/// Designed to allow composition of a FunctionPass(Manager) and
|
||||
/// a CGSCCPassManager. Note that if this pass is constructed with a pointer
|
||||
/// to a \c CGSCCAnalysisManager it will run the
|
||||
/// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function
|
||||
/// pass over the SCC to enable a \c FunctionAnalysisManager to be used
|
||||
/// within this run safely.
|
||||
template <typename FunctionPassT> class CGSCCToFunctionPassAdaptor {
|
||||
public:
|
||||
explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass)
|
||||
: Pass(std::move(Pass)) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg)
|
||||
: Pass(Arg.Pass) {}
|
||||
CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg)
|
||||
: Pass(std::move(Arg.Pass)) {}
|
||||
friend void swap(CGSCCToFunctionPassAdaptor &LHS, CGSCCToFunctionPassAdaptor &RHS) {
|
||||
using std::swap;
|
||||
swap(LHS.Pass, RHS.Pass);
|
||||
}
|
||||
CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) {
|
||||
swap(*this, RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Runs the function pass across every function in the module.
|
||||
PreservedAnalyses run(LazyCallGraph::SCC *C, CGSCCAnalysisManager *AM) {
|
||||
FunctionAnalysisManager *FAM = nullptr;
|
||||
if (AM)
|
||||
// Setup the function analysis manager from its proxy.
|
||||
FAM = &AM->getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
for (LazyCallGraph::Node *N : *C) {
|
||||
PreservedAnalyses PassPA = Pass.run(&N->getFunction(), FAM);
|
||||
|
||||
// We know that the function pass couldn't have invalidated any other
|
||||
// function's analyses (that's the contract of a function pass), so
|
||||
// directly handle the function analysis manager's invalidation here.
|
||||
if (FAM)
|
||||
FAM->invalidate(&N->getFunction(), PassPA);
|
||||
|
||||
// Then intersect the preserved set so that invalidation of module
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
PA.intersect(std::move(PassPA));
|
||||
}
|
||||
|
||||
// By definition we preserve the proxy. This precludes *any* invalidation
|
||||
// of function analyses by the proxy, but that's OK because we've taken
|
||||
// care to invalidate analyses in the function analysis manager
|
||||
// incrementally above.
|
||||
// FIXME: We need to update the call graph here to account for any deleted
|
||||
// edges!
|
||||
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
|
||||
return PA;
|
||||
}
|
||||
|
||||
static StringRef name() { return "CGSCCToFunctionPassAdaptor"; }
|
||||
|
||||
private:
|
||||
FunctionPassT Pass;
|
||||
};
|
||||
|
||||
/// \brief A function to deduce a function pass type and wrap it in the
|
||||
/// templated adaptor.
|
||||
template <typename FunctionPassT>
|
||||
CGSCCToFunctionPassAdaptor<FunctionPassT>
|
||||
createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) {
|
||||
return std::move(CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -6,46 +6,47 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This interface is used to build and manipulate a call graph, which is a very
|
||||
// useful tool for interprocedural optimization.
|
||||
//
|
||||
// Every function in a module is represented as a node in the call graph. The
|
||||
// callgraph node keeps track of which functions the are called by the function
|
||||
// corresponding to the node.
|
||||
//
|
||||
// A call graph may contain nodes where the function that they correspond to is
|
||||
// null. These 'external' nodes are used to represent control flow that is not
|
||||
// represented (or analyzable) in the module. In particular, this analysis
|
||||
// builds one external node such that:
|
||||
// 1. All functions in the module without internal linkage will have edges
|
||||
// from this external node, indicating that they could be called by
|
||||
// functions outside of the module.
|
||||
// 2. All functions whose address is used for something more than a direct
|
||||
// call, for example being stored into a memory location will also have an
|
||||
// edge from this external node. Since they may be called by an unknown
|
||||
// caller later, they must be tracked as such.
|
||||
//
|
||||
// There is a second external node added for calls that leave this module.
|
||||
// Functions have a call edge to the external node iff:
|
||||
// 1. The function is external, reflecting the fact that they could call
|
||||
// anything without internal linkage or that has its address taken.
|
||||
// 2. The function contains an indirect function call.
|
||||
//
|
||||
// As an extension in the future, there may be multiple nodes with a null
|
||||
// function. These will be used when we can prove (through pointer analysis)
|
||||
// that an indirect call site can call only a specific set of functions.
|
||||
//
|
||||
// Because of these properties, the CallGraph captures a conservative superset
|
||||
// of all of the caller-callee relationships, which is useful for
|
||||
// transformations.
|
||||
//
|
||||
// The CallGraph class also attempts to figure out what the root of the
|
||||
// CallGraph is, which it currently does by looking for a function named 'main'.
|
||||
// If no function named 'main' is found, the external node is used as the entry
|
||||
// node, reflecting the fact that any function without internal linkage could
|
||||
// be called into (which is common for libraries).
|
||||
//
|
||||
/// \file
|
||||
///
|
||||
/// This file provides interfaces used to build and manipulate a call graph,
|
||||
/// which is a very useful tool for interprocedural optimization.
|
||||
///
|
||||
/// Every function in a module is represented as a node in the call graph. The
|
||||
/// callgraph node keeps track of which functions are called by the function
|
||||
/// corresponding to the node.
|
||||
///
|
||||
/// A call graph may contain nodes where the function that they correspond to
|
||||
/// is null. These 'external' nodes are used to represent control flow that is
|
||||
/// not represented (or analyzable) in the module. In particular, this
|
||||
/// analysis builds one external node such that:
|
||||
/// 1. All functions in the module without internal linkage will have edges
|
||||
/// from this external node, indicating that they could be called by
|
||||
/// functions outside of the module.
|
||||
/// 2. All functions whose address is used for something more than a direct
|
||||
/// call, for example being stored into a memory location will also have
|
||||
/// an edge from this external node. Since they may be called by an
|
||||
/// unknown caller later, they must be tracked as such.
|
||||
///
|
||||
/// There is a second external node added for calls that leave this module.
|
||||
/// Functions have a call edge to the external node iff:
|
||||
/// 1. The function is external, reflecting the fact that they could call
|
||||
/// anything without internal linkage or that has its address taken.
|
||||
/// 2. The function contains an indirect function call.
|
||||
///
|
||||
/// As an extension in the future, there may be multiple nodes with a null
|
||||
/// function. These will be used when we can prove (through pointer analysis)
|
||||
/// that an indirect call site can call only a specific set of functions.
|
||||
///
|
||||
/// Because of these properties, the CallGraph captures a conservative superset
|
||||
/// of all of the caller-callee relationships, which is useful for
|
||||
/// transformations.
|
||||
///
|
||||
/// The CallGraph class also attempts to figure out what the root of the
|
||||
/// CallGraph is, which it currently does by looking for a function named
|
||||
/// 'main'. If no function named 'main' is found, the external node is used as
|
||||
/// the entry node, reflecting the fact that any function without internal
|
||||
/// linkage could be called into (which is common for libraries).
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CALLGRAPH_H
|
||||
@ -53,11 +54,11 @@
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Support/IncludeFile.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
@ -66,171 +67,142 @@ class Function;
|
||||
class Module;
|
||||
class CallGraphNode;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CallGraph class definition
|
||||
//
|
||||
class CallGraph : public ModulePass {
|
||||
Module *Mod; // The module this call graph represents
|
||||
/// \brief The basic data container for the call graph of a \c Module of IR.
|
||||
///
|
||||
/// This class exposes both the interface to the call graph for a module of IR.
|
||||
///
|
||||
/// The core call graph itself can also be updated to reflect changes to the IR.
|
||||
class CallGraph {
|
||||
Module &M;
|
||||
|
||||
typedef std::map<const Function *, CallGraphNode *> FunctionMapTy;
|
||||
FunctionMapTy FunctionMap; // Map from a function to its node
|
||||
|
||||
// Root is root of the call graph, or the external node if a 'main' function
|
||||
// couldn't be found.
|
||||
//
|
||||
/// \brief A map from \c Function* to \c CallGraphNode*.
|
||||
FunctionMapTy FunctionMap;
|
||||
|
||||
/// \brief Root is root of the call graph, or the external node if a 'main'
|
||||
/// function couldn't be found.
|
||||
CallGraphNode *Root;
|
||||
|
||||
// ExternalCallingNode - This node has edges to all external functions and
|
||||
// those internal functions that have their address taken.
|
||||
/// \brief This node has edges to all external functions and those internal
|
||||
/// functions that have their address taken.
|
||||
CallGraphNode *ExternalCallingNode;
|
||||
|
||||
// CallsExternalNode - This node has edges to it from all functions making
|
||||
// indirect calls or calling an external function.
|
||||
/// \brief This node has edges to it from all functions making indirect calls
|
||||
/// or calling an external function.
|
||||
CallGraphNode *CallsExternalNode;
|
||||
|
||||
/// Replace the function represented by this node by another.
|
||||
/// \brief Replace the function represented by this node by another.
|
||||
///
|
||||
/// This does not rescan the body of the function, so it is suitable when
|
||||
/// splicing the body of one function to another while also updating all
|
||||
/// callers from the old function to the new.
|
||||
///
|
||||
void spliceFunction(const Function *From, const Function *To);
|
||||
|
||||
// Add a function to the call graph, and link the node to all of the functions
|
||||
// that it calls.
|
||||
/// \brief Add a function to the call graph, and link the node to all of the
|
||||
/// functions that it calls.
|
||||
void addToCallGraph(Function *F);
|
||||
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
//===---------------------------------------------------------------------
|
||||
// Accessors.
|
||||
//
|
||||
CallGraph(Module &M);
|
||||
~CallGraph();
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
typedef FunctionMapTy::iterator iterator;
|
||||
typedef FunctionMapTy::const_iterator const_iterator;
|
||||
|
||||
/// getModule - Return the module the call graph corresponds to.
|
||||
///
|
||||
Module &getModule() const { return *Mod; }
|
||||
/// \brief Returns the module the call graph corresponds to.
|
||||
Module &getModule() const { return M; }
|
||||
|
||||
inline iterator begin() { return FunctionMap.begin(); }
|
||||
inline iterator end() { return FunctionMap.end(); }
|
||||
inline iterator begin() { return FunctionMap.begin(); }
|
||||
inline iterator end() { return FunctionMap.end(); }
|
||||
inline const_iterator begin() const { return FunctionMap.begin(); }
|
||||
inline const_iterator end() const { return FunctionMap.end(); }
|
||||
inline const_iterator end() const { return FunctionMap.end(); }
|
||||
|
||||
// Subscripting operators, return the call graph node for the provided
|
||||
// function
|
||||
/// \brief Returns the call graph node for the provided function.
|
||||
inline const CallGraphNode *operator[](const Function *F) const {
|
||||
const_iterator I = FunctionMap.find(F);
|
||||
assert(I != FunctionMap.end() && "Function not in callgraph!");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// \brief Returns the call graph node for the provided function.
|
||||
inline CallGraphNode *operator[](const Function *F) {
|
||||
const_iterator I = FunctionMap.find(F);
|
||||
assert(I != FunctionMap.end() && "Function not in callgraph!");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// Returns the CallGraphNode which is used to represent undetermined calls
|
||||
/// into the callgraph.
|
||||
/// \brief Returns the \c CallGraphNode which is used to represent
|
||||
/// undetermined calls into the callgraph.
|
||||
CallGraphNode *getExternalCallingNode() const { return ExternalCallingNode; }
|
||||
CallGraphNode *getCallsExternalNode() const { return CallsExternalNode; }
|
||||
|
||||
/// Return the root/main method in the module, or some other root node, such
|
||||
/// as the externalcallingnode.
|
||||
CallGraphNode *getRoot() { return Root; }
|
||||
const CallGraphNode *getRoot() const { return Root; }
|
||||
CallGraphNode *getCallsExternalNode() const { return CallsExternalNode; }
|
||||
|
||||
//===---------------------------------------------------------------------
|
||||
// Functions to keep a call graph up to date with a function that has been
|
||||
// modified.
|
||||
//
|
||||
|
||||
/// removeFunctionFromModule - Unlink the function from this module, returning
|
||||
/// it. Because this removes the function from the module, the call graph
|
||||
/// node is destroyed. This is only valid if the function does not call any
|
||||
/// other functions (ie, there are no edges in it's CGN). The easiest way to
|
||||
/// do this is to dropAllReferences before calling this.
|
||||
/// \brief Unlink the function from this module, returning it.
|
||||
///
|
||||
/// Because this removes the function from the module, the call graph node is
|
||||
/// destroyed. This is only valid if the function does not call any other
|
||||
/// functions (ie, there are no edges in it's CGN). The easiest way to do
|
||||
/// this is to dropAllReferences before calling this.
|
||||
Function *removeFunctionFromModule(CallGraphNode *CGN);
|
||||
|
||||
/// getOrInsertFunction - This method is identical to calling operator[], but
|
||||
/// it will insert a new CallGraphNode for the specified function if one does
|
||||
/// not already exist.
|
||||
/// \brief Similar to operator[], but this will insert a new CallGraphNode for
|
||||
/// \c F if one does not already exist.
|
||||
CallGraphNode *getOrInsertFunction(const Function *F);
|
||||
|
||||
CallGraph();
|
||||
virtual ~CallGraph() { releaseMemory(); }
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
virtual bool runOnModule(Module &M);
|
||||
virtual void releaseMemory();
|
||||
|
||||
void print(raw_ostream &o, const Module *) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CallGraphNode class definition.
|
||||
//
|
||||
/// \brief A node in the call graph for a module.
|
||||
///
|
||||
/// Typically represents a function in the call graph. There are also special
|
||||
/// "null" nodes used to represent theoretical entries in the call graph.
|
||||
class CallGraphNode {
|
||||
friend class CallGraph;
|
||||
|
||||
AssertingVH<Function> F;
|
||||
|
||||
// CallRecord - This is a pair of the calling instruction (a call or invoke)
|
||||
// and the callgraph node being called.
|
||||
public:
|
||||
typedef std::pair<WeakVH, CallGraphNode*> CallRecord;
|
||||
private:
|
||||
std::vector<CallRecord> CalledFunctions;
|
||||
|
||||
/// NumReferences - This is the number of times that this CallGraphNode occurs
|
||||
/// in the CalledFunctions array of this or other CallGraphNodes.
|
||||
unsigned NumReferences;
|
||||
/// \brief A pair of the calling instruction (a call or invoke)
|
||||
/// and the call graph node being called.
|
||||
typedef std::pair<WeakVH, CallGraphNode *> CallRecord;
|
||||
|
||||
CallGraphNode(const CallGraphNode &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CallGraphNode &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
void DropRef() { --NumReferences; }
|
||||
void AddRef() { ++NumReferences; }
|
||||
public:
|
||||
typedef std::vector<CallRecord> CalledFunctionsVector;
|
||||
|
||||
|
||||
// CallGraphNode ctor - Create a node for the specified function.
|
||||
inline CallGraphNode(Function *f) : F(f), NumReferences(0) {}
|
||||
/// \brief Creates a node for the specified function.
|
||||
inline CallGraphNode(Function *F) : F(F), NumReferences(0) {}
|
||||
|
||||
~CallGraphNode() {
|
||||
assert(NumReferences == 0 && "Node deleted while references remain");
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------
|
||||
// Accessor methods.
|
||||
//
|
||||
|
||||
typedef std::vector<CallRecord>::iterator iterator;
|
||||
typedef std::vector<CallRecord>::const_iterator const_iterator;
|
||||
|
||||
// getFunction - Return the function that this call graph node represents.
|
||||
/// \brief Returns the function that this call graph node represents.
|
||||
Function *getFunction() const { return F; }
|
||||
|
||||
inline iterator begin() { return CalledFunctions.begin(); }
|
||||
inline iterator end() { return CalledFunctions.end(); }
|
||||
inline iterator end() { return CalledFunctions.end(); }
|
||||
inline const_iterator begin() const { return CalledFunctions.begin(); }
|
||||
inline const_iterator end() const { return CalledFunctions.end(); }
|
||||
inline const_iterator end() const { return CalledFunctions.end(); }
|
||||
inline bool empty() const { return CalledFunctions.empty(); }
|
||||
inline unsigned size() const { return (unsigned)CalledFunctions.size(); }
|
||||
|
||||
/// getNumReferences - Return the number of other CallGraphNodes in this
|
||||
/// CallGraph that reference this node in their callee list.
|
||||
/// \brief Returns the number of other CallGraphNodes in this CallGraph that
|
||||
/// reference this node in their callee list.
|
||||
unsigned getNumReferences() const { return NumReferences; }
|
||||
|
||||
// Subscripting operator - Return the i'th called function.
|
||||
//
|
||||
|
||||
/// \brief Returns the i'th called function.
|
||||
CallGraphNode *operator[](unsigned i) const {
|
||||
assert(i < CalledFunctions.size() && "Invalid index");
|
||||
return CalledFunctions[i].second;
|
||||
}
|
||||
|
||||
/// dump - Print out this call graph node.
|
||||
///
|
||||
/// \brief Print out this call graph node.
|
||||
void dump() const;
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
@ -239,29 +211,25 @@ public:
|
||||
// modified
|
||||
//
|
||||
|
||||
/// removeAllCalledFunctions - As the name implies, this removes all edges
|
||||
/// from this CallGraphNode to any functions it calls.
|
||||
/// \brief Removes all edges from this CallGraphNode to any functions it
|
||||
/// calls.
|
||||
void removeAllCalledFunctions() {
|
||||
while (!CalledFunctions.empty()) {
|
||||
CalledFunctions.back().second->DropRef();
|
||||
CalledFunctions.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/// stealCalledFunctionsFrom - Move all the callee information from N to this
|
||||
/// node.
|
||||
|
||||
/// \brief Moves all the callee information from N to this node.
|
||||
void stealCalledFunctionsFrom(CallGraphNode *N) {
|
||||
assert(CalledFunctions.empty() &&
|
||||
"Cannot steal callsite information if I already have some");
|
||||
std::swap(CalledFunctions, N->CalledFunctions);
|
||||
}
|
||||
|
||||
|
||||
/// addCalledFunction - Add a function to the list of functions called by this
|
||||
/// one.
|
||||
/// \brief Adds a function to the list of functions called by this one.
|
||||
void addCalledFunction(CallSite CS, CallGraphNode *M) {
|
||||
assert(!CS.getInstruction() ||
|
||||
!CS.getCalledFunction() ||
|
||||
assert(!CS.getInstruction() || !CS.getCalledFunction() ||
|
||||
!CS.getCalledFunction()->isIntrinsic());
|
||||
CalledFunctions.push_back(std::make_pair(CS.getInstruction(), M));
|
||||
M->AddRef();
|
||||
@ -272,32 +240,152 @@ public:
|
||||
*I = CalledFunctions.back();
|
||||
CalledFunctions.pop_back();
|
||||
}
|
||||
|
||||
|
||||
/// removeCallEdgeFor - This method removes the edge in the node for the
|
||||
/// specified call site. Note that this method takes linear time, so it
|
||||
/// should be used sparingly.
|
||||
|
||||
/// \brief Removes the edge in the node for the specified call site.
|
||||
///
|
||||
/// Note that this method takes linear time, so it should be used sparingly.
|
||||
void removeCallEdgeFor(CallSite CS);
|
||||
|
||||
/// removeAnyCallEdgeTo - This method removes all call edges from this node
|
||||
/// to the specified callee function. This takes more time to execute than
|
||||
/// removeCallEdgeTo, so it should not be used unless necessary.
|
||||
/// \brief Removes all call edges from this node to the specified callee
|
||||
/// function.
|
||||
///
|
||||
/// This takes more time to execute than removeCallEdgeTo, so it should not
|
||||
/// be used unless necessary.
|
||||
void removeAnyCallEdgeTo(CallGraphNode *Callee);
|
||||
|
||||
/// removeOneAbstractEdgeTo - Remove one edge associated with a null callsite
|
||||
/// from this node to the specified callee function.
|
||||
/// \brief Removes one edge associated with a null callsite from this node to
|
||||
/// the specified callee function.
|
||||
void removeOneAbstractEdgeTo(CallGraphNode *Callee);
|
||||
|
||||
/// replaceCallEdge - This method replaces the edge in the node for the
|
||||
/// specified call site with a new one. Note that this method takes linear
|
||||
/// time, so it should be used sparingly.
|
||||
|
||||
/// \brief Replaces the edge in the node for the specified call site with a
|
||||
/// new one.
|
||||
///
|
||||
/// Note that this method takes linear time, so it should be used sparingly.
|
||||
void replaceCallEdge(CallSite CS, CallSite NewCS, CallGraphNode *NewNode);
|
||||
|
||||
/// allReferencesDropped - This is a special function that should only be
|
||||
/// used by the CallGraph class.
|
||||
void allReferencesDropped() {
|
||||
NumReferences = 0;
|
||||
|
||||
private:
|
||||
friend class CallGraph;
|
||||
|
||||
AssertingVH<Function> F;
|
||||
|
||||
std::vector<CallRecord> CalledFunctions;
|
||||
|
||||
/// \brief The number of times that this CallGraphNode occurs in the
|
||||
/// CalledFunctions array of this or other CallGraphNodes.
|
||||
unsigned NumReferences;
|
||||
|
||||
CallGraphNode(const CallGraphNode &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CallGraphNode &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
void DropRef() { --NumReferences; }
|
||||
void AddRef() { ++NumReferences; }
|
||||
|
||||
/// \brief A special function that should only be used by the CallGraph class.
|
||||
void allReferencesDropped() { NumReferences = 0; }
|
||||
};
|
||||
|
||||
/// \brief An analysis pass to compute the \c CallGraph for a \c Module.
|
||||
///
|
||||
/// This class implements the concept of an analysis pass used by the \c
|
||||
/// ModuleAnalysisManager to run an analysis over a module and cache the
|
||||
/// resulting data.
|
||||
class CallGraphAnalysis {
|
||||
public:
|
||||
/// \brief A formulaic typedef to inform clients of the result type.
|
||||
typedef CallGraph Result;
|
||||
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Compute the \c CallGraph for the module \c M.
|
||||
///
|
||||
/// The real work here is done in the \c CallGraph constructor.
|
||||
CallGraph run(Module *M) { return CallGraph(*M); }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
};
|
||||
|
||||
/// \brief The \c ModulePass which wraps up a \c CallGraph and the logic to
|
||||
/// build it.
|
||||
///
|
||||
/// This class exposes both the interface to the call graph container and the
|
||||
/// module pass which runs over a module of IR and produces the call graph. The
|
||||
/// call graph interface is entirelly a wrapper around a \c CallGraph object
|
||||
/// which is stored internally for each module.
|
||||
class CallGraphWrapperPass : public ModulePass {
|
||||
std::unique_ptr<CallGraph> G;
|
||||
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
|
||||
CallGraphWrapperPass();
|
||||
virtual ~CallGraphWrapperPass();
|
||||
|
||||
/// \brief The internal \c CallGraph around which the rest of this interface
|
||||
/// is wrapped.
|
||||
const CallGraph &getCallGraph() const { return *G; }
|
||||
CallGraph &getCallGraph() { return *G; }
|
||||
|
||||
typedef CallGraph::iterator iterator;
|
||||
typedef CallGraph::const_iterator const_iterator;
|
||||
|
||||
/// \brief Returns the module the call graph corresponds to.
|
||||
Module &getModule() const { return G->getModule(); }
|
||||
|
||||
inline iterator begin() { return G->begin(); }
|
||||
inline iterator end() { return G->end(); }
|
||||
inline const_iterator begin() const { return G->begin(); }
|
||||
inline const_iterator end() const { return G->end(); }
|
||||
|
||||
/// \brief Returns the call graph node for the provided function.
|
||||
inline const CallGraphNode *operator[](const Function *F) const {
|
||||
return (*G)[F];
|
||||
}
|
||||
|
||||
/// \brief Returns the call graph node for the provided function.
|
||||
inline CallGraphNode *operator[](const Function *F) { return (*G)[F]; }
|
||||
|
||||
/// \brief Returns the \c CallGraphNode which is used to represent
|
||||
/// undetermined calls into the callgraph.
|
||||
CallGraphNode *getExternalCallingNode() const {
|
||||
return G->getExternalCallingNode();
|
||||
}
|
||||
|
||||
CallGraphNode *getCallsExternalNode() const {
|
||||
return G->getCallsExternalNode();
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------
|
||||
// Functions to keep a call graph up to date with a function that has been
|
||||
// modified.
|
||||
//
|
||||
|
||||
/// \brief Unlink the function from this module, returning it.
|
||||
///
|
||||
/// Because this removes the function from the module, the call graph node is
|
||||
/// destroyed. This is only valid if the function does not call any other
|
||||
/// functions (ie, there are no edges in it's CGN). The easiest way to do
|
||||
/// this is to dropAllReferences before calling this.
|
||||
Function *removeFunctionFromModule(CallGraphNode *CGN) {
|
||||
return G->removeFunctionFromModule(CGN);
|
||||
}
|
||||
|
||||
/// \brief Similar to operator[], but this will insert a new CallGraphNode for
|
||||
/// \c F if one does not already exist.
|
||||
CallGraphNode *getOrInsertFunction(const Function *F) {
|
||||
return G->getOrInsertFunction(F);
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------
|
||||
// Implementation of the ModulePass interface needed here.
|
||||
//
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnModule(Module &M) override;
|
||||
void releaseMemory() override;
|
||||
|
||||
void print(raw_ostream &o, const Module *) const override;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -307,11 +395,12 @@ public:
|
||||
|
||||
// Provide graph traits for tranversing call graphs using standard graph
|
||||
// traversals.
|
||||
template <> struct GraphTraits<CallGraphNode*> {
|
||||
template <> struct GraphTraits<CallGraphNode *> {
|
||||
typedef CallGraphNode NodeType;
|
||||
|
||||
typedef CallGraphNode::CallRecord CGNPairTy;
|
||||
typedef std::pointer_to_unary_function<CGNPairTy, CallGraphNode*> CGNDerefFun;
|
||||
typedef std::pointer_to_unary_function<CGNPairTy, CallGraphNode *>
|
||||
CGNDerefFun;
|
||||
|
||||
static NodeType *getEntryNode(CallGraphNode *CGN) { return CGN; }
|
||||
|
||||
@ -320,55 +409,54 @@ template <> struct GraphTraits<CallGraphNode*> {
|
||||
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
static inline ChildIteratorType child_end (NodeType *N) {
|
||||
static inline ChildIteratorType child_end(NodeType *N) {
|
||||
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
|
||||
static CallGraphNode *CGNDeref(CGNPairTy P) {
|
||||
return P.second;
|
||||
}
|
||||
|
||||
static CallGraphNode *CGNDeref(CGNPairTy P) { return P.second; }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const CallGraphNode*> {
|
||||
template <> struct GraphTraits<const CallGraphNode *> {
|
||||
typedef const CallGraphNode NodeType;
|
||||
typedef NodeType::const_iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(const CallGraphNode *CGN) { return CGN; }
|
||||
static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();}
|
||||
static inline ChildIteratorType child_end (NodeType *N) { return N->end(); }
|
||||
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||
return N->begin();
|
||||
}
|
||||
static inline ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
template<> struct GraphTraits<CallGraph*> : public GraphTraits<CallGraphNode*> {
|
||||
template <>
|
||||
struct GraphTraits<CallGraph *> : public GraphTraits<CallGraphNode *> {
|
||||
static NodeType *getEntryNode(CallGraph *CGN) {
|
||||
return CGN->getExternalCallingNode(); // Start at the external node!
|
||||
return CGN->getExternalCallingNode(); // Start at the external node!
|
||||
}
|
||||
typedef std::pair<const Function*, CallGraphNode*> PairTy;
|
||||
typedef std::pointer_to_unary_function<PairTy, CallGraphNode&> DerefFun;
|
||||
typedef std::pair<const Function *, CallGraphNode *> PairTy;
|
||||
typedef std::pointer_to_unary_function<PairTy, CallGraphNode &> DerefFun;
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef mapped_iterator<CallGraph::iterator, DerefFun> nodes_iterator;
|
||||
static nodes_iterator nodes_begin(CallGraph *CG) {
|
||||
return map_iterator(CG->begin(), DerefFun(CGdereference));
|
||||
}
|
||||
static nodes_iterator nodes_end (CallGraph *CG) {
|
||||
static nodes_iterator nodes_end(CallGraph *CG) {
|
||||
return map_iterator(CG->end(), DerefFun(CGdereference));
|
||||
}
|
||||
|
||||
static CallGraphNode &CGdereference(PairTy P) {
|
||||
return *P.second;
|
||||
}
|
||||
static CallGraphNode &CGdereference(PairTy P) { return *P.second; }
|
||||
};
|
||||
|
||||
template<> struct GraphTraits<const CallGraph*> :
|
||||
public GraphTraits<const CallGraphNode*> {
|
||||
template <>
|
||||
struct GraphTraits<const CallGraph *> : public GraphTraits<
|
||||
const CallGraphNode *> {
|
||||
static NodeType *getEntryNode(const CallGraph *CGN) {
|
||||
return CGN->getExternalCallingNode();
|
||||
}
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef CallGraph::const_iterator nodes_iterator;
|
||||
static nodes_iterator nodes_begin(const CallGraph *CG) { return CG->begin(); }
|
||||
static nodes_iterator nodes_end (const CallGraph *CG) { return CG->end(); }
|
||||
static nodes_iterator nodes_end(const CallGraph *CG) { return CG->end(); }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -37,7 +37,8 @@ public:
|
||||
|
||||
/// createPrinterPass - Get a pass that prints the Module
|
||||
/// corresponding to a CallGraph.
|
||||
Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const;
|
||||
Pass *createPrinterPass(raw_ostream &O,
|
||||
const std::string &Banner) const override;
|
||||
|
||||
using llvm::Pass::doInitialization;
|
||||
using llvm::Pass::doFinalization;
|
||||
@ -65,18 +66,17 @@ public:
|
||||
}
|
||||
|
||||
/// Assign pass manager to manager this pass
|
||||
virtual void assignPassManager(PMStack &PMS,
|
||||
PassManagerType PMT);
|
||||
void assignPassManager(PMStack &PMS, PassManagerType PMT) override;
|
||||
|
||||
/// Return what kind of Pass Manager can manage this pass.
|
||||
virtual PassManagerType getPotentialPassManagerType() const {
|
||||
PassManagerType getPotentialPassManagerType() const override {
|
||||
return PMT_CallGraphPassManager;
|
||||
}
|
||||
|
||||
/// getAnalysisUsage - For this class, we declare that we require and preserve
|
||||
/// the call graph. If the derived class implements this method, it should
|
||||
/// always explicitly call the implementation here.
|
||||
virtual void getAnalysisUsage(AnalysisUsage &Info) const;
|
||||
void getAnalysisUsage(AnalysisUsage &Info) const override;
|
||||
};
|
||||
|
||||
/// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
|
||||
|
@ -18,6 +18,8 @@ namespace llvm {
|
||||
|
||||
class Value;
|
||||
class Use;
|
||||
class Instruction;
|
||||
class DominatorTree;
|
||||
|
||||
/// PointerMayBeCaptured - Return true if this pointer value may be captured
|
||||
/// by the enclosing function (which is required to exist). This routine can
|
||||
@ -30,6 +32,20 @@ namespace llvm {
|
||||
bool ReturnCaptures,
|
||||
bool StoreCaptures);
|
||||
|
||||
/// PointerMayBeCapturedBefore - Return true if this pointer value may be
|
||||
/// captured by the enclosing function (which is required to exist). If a
|
||||
/// DominatorTree is provided, only captures which happen before the given
|
||||
/// instruction are considered. This routine can be expensive, so consider
|
||||
/// caching the results. The boolean ReturnCaptures specifies whether
|
||||
/// returning the value (or part of it) from the function counts as capturing
|
||||
/// it or not. The boolean StoreCaptures specified whether storing the value
|
||||
/// (or part of it) into memory anywhere automatically counts as capturing it
|
||||
/// or not. Captures by the provided instruction are considered if the
|
||||
/// final parameter is true.
|
||||
bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
|
||||
bool StoreCaptures, const Instruction *I,
|
||||
DominatorTree *DT, bool IncludeI = false);
|
||||
|
||||
/// This callback is used in conjunction with PointerMayBeCaptured. In
|
||||
/// addition to the interface here, you'll need to provide your own getters
|
||||
/// to see whether anything was captured.
|
||||
@ -45,12 +61,12 @@ namespace llvm {
|
||||
/// capture) return false. To search it, return true.
|
||||
///
|
||||
/// U->getUser() is always an Instruction.
|
||||
virtual bool shouldExplore(Use *U);
|
||||
virtual bool shouldExplore(const Use *U);
|
||||
|
||||
/// captured - Information about the pointer was captured by the user of
|
||||
/// use U. Return true to stop the traversal or false to continue looking
|
||||
/// for more capturing instructions.
|
||||
virtual bool captured(Use *U) = 0;
|
||||
virtual bool captured(const Use *U) = 0;
|
||||
};
|
||||
|
||||
/// PointerMayBeCaptured - Visit the value and the values derived from it and
|
||||
|
@ -16,7 +16,7 @@
|
||||
#define LLVM_ANALYSIS_CODEMETRICS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
|
||||
namespace llvm {
|
||||
class BasicBlock;
|
||||
|
@ -36,15 +36,16 @@ namespace llvm {
|
||||
/// Note that this fails if not all of the operands are constant. Otherwise,
|
||||
/// this function can only fail when attempting to fold instructions like loads
|
||||
/// and stores, which have no constant expression form.
|
||||
Constant *ConstantFoldInstruction(Instruction *I, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0);
|
||||
Constant *ConstantFoldInstruction(Instruction *I,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldConstantExpression - Attempt to fold the constant expression
|
||||
/// using the specified DataLayout. If successful, the constant result is
|
||||
/// result is returned, if not, null is returned.
|
||||
Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI =nullptr);
|
||||
|
||||
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
|
||||
/// specified operands. If successful, the constant result is returned, if not,
|
||||
@ -54,8 +55,8 @@ Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
|
||||
///
|
||||
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
|
||||
ArrayRef<Constant *> Ops,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
|
||||
/// instruction (icmp/fcmp) with the specified operands. If it fails, it
|
||||
@ -63,8 +64,8 @@ Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
|
||||
///
|
||||
Constant *ConstantFoldCompareInstOperands(unsigned Predicate,
|
||||
Constant *LHS, Constant *RHS,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI=nullptr);
|
||||
|
||||
/// ConstantFoldInsertValueInstruction - Attempt to constant fold an insertvalue
|
||||
/// instruction with the specified operands and indices. The constant result is
|
||||
@ -75,7 +76,8 @@ Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
|
||||
/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would
|
||||
/// produce if it is constant and determinable. If this is not determinable,
|
||||
/// return null.
|
||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout *TD = 0);
|
||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C,
|
||||
const DataLayout *TD = nullptr);
|
||||
|
||||
/// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a
|
||||
/// getelementptr constantexpr, return the constant value being addressed by the
|
||||
@ -96,7 +98,7 @@ bool canConstantFoldCallTo(const Function *F);
|
||||
/// ConstantFoldCall - Attempt to constant fold a call to the specified function
|
||||
/// with the specified arguments, returning null if unsuccessful.
|
||||
Constant *ConstantFoldCall(Function *F, ArrayRef<Constant *> Operands,
|
||||
const TargetLibraryInfo *TLI = 0);
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -16,7 +16,7 @@
|
||||
#ifndef LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
||||
#define LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
||||
|
||||
#include "llvm/Support/InstIterator.h"
|
||||
#include "llvm/IR/InstIterator.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
@ -16,53 +16,66 @@
|
||||
|
||||
#include "llvm/Analysis/CFGPrinter.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <class Analysis, bool Simple>
|
||||
/// \brief Default traits class for extracting a graph from an analysis pass.
|
||||
///
|
||||
/// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through.
|
||||
template <typename AnalysisT, typename GraphT = AnalysisT *>
|
||||
struct DefaultAnalysisGraphTraits {
|
||||
static GraphT getGraph(AnalysisT *A) { return A; }
|
||||
};
|
||||
|
||||
template <
|
||||
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||
class DOTGraphTraitsViewer : public FunctionPass {
|
||||
public:
|
||||
DOTGraphTraitsViewer(StringRef GraphName, char &ID)
|
||||
: FunctionPass(ID), Name(GraphName) {}
|
||||
: FunctionPass(ID), Name(GraphName) {}
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
Analysis *Graph = &getAnalysis<Analysis>();
|
||||
std::string GraphName = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
||||
bool runOnFunction(Function &F) override {
|
||||
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
||||
|
||||
ViewGraph(Graph, Name, Simple, Title);
|
||||
ViewGraph(Graph, Name, IsSimple, Title);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<Analysis>();
|
||||
AU.addRequired<AnalysisT>();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string Name;
|
||||
};
|
||||
|
||||
template <class Analysis, bool Simple>
|
||||
template <
|
||||
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||
class DOTGraphTraitsPrinter : public FunctionPass {
|
||||
public:
|
||||
DOTGraphTraitsPrinter(StringRef GraphName, char &ID)
|
||||
: FunctionPass(ID), Name(GraphName) {}
|
||||
: FunctionPass(ID), Name(GraphName) {}
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
Analysis *Graph = &getAnalysis<Analysis>();
|
||||
bool runOnFunction(Function &F) override {
|
||||
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||
std::string Filename = Name + "." + F.getName().str() + ".dot";
|
||||
std::string ErrorInfo;
|
||||
|
||||
errs() << "Writing '" << Filename << "'...";
|
||||
|
||||
raw_fd_ostream File(Filename.c_str(), ErrorInfo);
|
||||
std::string GraphName = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
||||
raw_fd_ostream File(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
|
||||
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
||||
|
||||
if (ErrorInfo.empty())
|
||||
WriteGraph(File, Graph, Simple, Title);
|
||||
WriteGraph(File, Graph, IsSimple, Title);
|
||||
else
|
||||
errs() << " error opening file for writing!";
|
||||
errs() << "\n";
|
||||
@ -70,57 +83,61 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<Analysis>();
|
||||
AU.addRequired<AnalysisT>();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string Name;
|
||||
};
|
||||
|
||||
template <class Analysis, bool Simple>
|
||||
template <
|
||||
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||
class DOTGraphTraitsModuleViewer : public ModulePass {
|
||||
public:
|
||||
DOTGraphTraitsModuleViewer(StringRef GraphName, char &ID)
|
||||
: ModulePass(ID), Name(GraphName) {}
|
||||
: ModulePass(ID), Name(GraphName) {}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
Analysis *Graph = &getAnalysis<Analysis>();
|
||||
std::string Title = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
||||
bool runOnModule(Module &M) override {
|
||||
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||
|
||||
ViewGraph(Graph, Name, Simple, Title);
|
||||
ViewGraph(Graph, Name, IsSimple, Title);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<Analysis>();
|
||||
AU.addRequired<AnalysisT>();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string Name;
|
||||
};
|
||||
|
||||
template <class Analysis, bool Simple>
|
||||
template <
|
||||
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||
class DOTGraphTraitsModulePrinter : public ModulePass {
|
||||
public:
|
||||
DOTGraphTraitsModulePrinter(StringRef GraphName, char &ID)
|
||||
: ModulePass(ID), Name(GraphName) {}
|
||||
: ModulePass(ID), Name(GraphName) {}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
Analysis *Graph = &getAnalysis<Analysis>();
|
||||
bool runOnModule(Module &M) override {
|
||||
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||
std::string Filename = Name + ".dot";
|
||||
std::string ErrorInfo;
|
||||
|
||||
errs() << "Writing '" << Filename << "'...";
|
||||
|
||||
raw_fd_ostream File(Filename.c_str(), ErrorInfo);
|
||||
std::string Title = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
||||
raw_fd_ostream File(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
|
||||
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||
|
||||
if (ErrorInfo.empty())
|
||||
WriteGraph(File, Graph, Simple, Title);
|
||||
WriteGraph(File, Graph, IsSimple, Title);
|
||||
else
|
||||
errs() << " error opening file for writing!";
|
||||
errs() << "\n";
|
||||
@ -128,9 +145,9 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<Analysis>();
|
||||
AU.addRequired<AnalysisT>();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -73,8 +73,8 @@ namespace llvm {
|
||||
Instruction *Destination) :
|
||||
Src(Source),
|
||||
Dst(Destination),
|
||||
NextPredecessor(NULL),
|
||||
NextSuccessor(NULL) {}
|
||||
NextPredecessor(nullptr),
|
||||
NextSuccessor(nullptr) {}
|
||||
virtual ~Dependence() {}
|
||||
|
||||
/// Dependence::DVEntry - Each level in the distance/direction vector
|
||||
@ -96,7 +96,7 @@ namespace llvm {
|
||||
bool Splitable : 1; // Splitting the loop will break dependence.
|
||||
const SCEV *Distance; // NULL implies no distance available.
|
||||
DVEntry() : Direction(ALL), Scalar(true), PeelFirst(false),
|
||||
PeelLast(false), Splitable(false), Distance(NULL) { }
|
||||
PeelLast(false), Splitable(false), Distance(nullptr) { }
|
||||
};
|
||||
|
||||
/// getSrc - Returns the source instruction for this dependence.
|
||||
@ -154,7 +154,7 @@ namespace llvm {
|
||||
|
||||
/// getDistance - Returns the distance (or NULL) associated with a
|
||||
/// particular level.
|
||||
virtual const SCEV *getDistance(unsigned Level) const { return NULL; }
|
||||
virtual const SCEV *getDistance(unsigned Level) const { return nullptr; }
|
||||
|
||||
/// isPeelFirst - Returns true if peeling the first iteration from
|
||||
/// this loop will break this dependence.
|
||||
@ -227,45 +227,45 @@ namespace llvm {
|
||||
|
||||
/// isLoopIndependent - Returns true if this is a loop-independent
|
||||
/// dependence.
|
||||
bool isLoopIndependent() const { return LoopIndependent; }
|
||||
bool isLoopIndependent() const override { return LoopIndependent; }
|
||||
|
||||
/// isConfused - Returns true if this dependence is confused
|
||||
/// (the compiler understands nothing and makes worst-case
|
||||
/// assumptions).
|
||||
bool isConfused() const { return false; }
|
||||
bool isConfused() const override { return false; }
|
||||
|
||||
/// isConsistent - Returns true if this dependence is consistent
|
||||
/// (occurs every time the source and destination are executed).
|
||||
bool isConsistent() const { return Consistent; }
|
||||
bool isConsistent() const override { return Consistent; }
|
||||
|
||||
/// getLevels - Returns the number of common loops surrounding the
|
||||
/// source and destination of the dependence.
|
||||
unsigned getLevels() const { return Levels; }
|
||||
unsigned getLevels() const override { return Levels; }
|
||||
|
||||
/// getDirection - Returns the direction associated with a particular
|
||||
/// level.
|
||||
unsigned getDirection(unsigned Level) const;
|
||||
unsigned getDirection(unsigned Level) const override;
|
||||
|
||||
/// getDistance - Returns the distance (or NULL) associated with a
|
||||
/// particular level.
|
||||
const SCEV *getDistance(unsigned Level) const;
|
||||
const SCEV *getDistance(unsigned Level) const override;
|
||||
|
||||
/// isPeelFirst - Returns true if peeling the first iteration from
|
||||
/// this loop will break this dependence.
|
||||
bool isPeelFirst(unsigned Level) const;
|
||||
bool isPeelFirst(unsigned Level) const override;
|
||||
|
||||
/// isPeelLast - Returns true if peeling the last iteration from
|
||||
/// this loop will break this dependence.
|
||||
bool isPeelLast(unsigned Level) const;
|
||||
bool isPeelLast(unsigned Level) const override;
|
||||
|
||||
/// isSplitable - Returns true if splitting the loop will break
|
||||
/// the dependence.
|
||||
bool isSplitable(unsigned Level) const;
|
||||
bool isSplitable(unsigned Level) const override;
|
||||
|
||||
/// isScalar - Returns true if a particular level is scalar; that is,
|
||||
/// if no subscript in the source or destination mention the induction
|
||||
/// variable associated with the loop at this level.
|
||||
bool isScalar(unsigned Level) const;
|
||||
bool isScalar(unsigned Level) const override;
|
||||
private:
|
||||
unsigned short Levels;
|
||||
bool LoopIndependent;
|
||||
@ -910,7 +910,8 @@ namespace llvm {
|
||||
const Constraint &CurConstraint) const;
|
||||
|
||||
bool tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
|
||||
SmallVectorImpl<Subscript> &Pair) const;
|
||||
SmallVectorImpl<Subscript> &Pair,
|
||||
const SCEV *ElementSize) const;
|
||||
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
@ -918,10 +919,10 @@ namespace llvm {
|
||||
initializeDependenceAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F);
|
||||
void releaseMemory();
|
||||
void getAnalysisUsage(AnalysisUsage &) const;
|
||||
void print(raw_ostream &, const Module * = 0) const;
|
||||
bool runOnFunction(Function &F) override;
|
||||
void releaseMemory() override;
|
||||
void getAnalysisUsage(AnalysisUsage &) const override;
|
||||
void print(raw_ostream &, const Module * = nullptr) const override;
|
||||
}; // class DependenceAnalysis
|
||||
|
||||
/// createDependenceAnalysisPass - This creates an instance of the
|
||||
|
@ -18,173 +18,191 @@
|
||||
#ifndef LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
||||
#define LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
||||
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DominanceFrontierBase - Common base class for computing forward and inverse
|
||||
/// dominance frontiers for a function.
|
||||
///
|
||||
class DominanceFrontierBase : public FunctionPass {
|
||||
template <class BlockT>
|
||||
class DominanceFrontierBase {
|
||||
public:
|
||||
typedef std::set<BasicBlock*> DomSetType; // Dom set for a bb
|
||||
typedef std::map<BasicBlock*, DomSetType> DomSetMapType; // Dom set map
|
||||
typedef std::set<BlockT *> DomSetType; // Dom set for a bb
|
||||
typedef std::map<BlockT *, DomSetType> DomSetMapType; // Dom set map
|
||||
|
||||
protected:
|
||||
typedef GraphTraits<BlockT *> BlockTraits;
|
||||
|
||||
DomSetMapType Frontiers;
|
||||
std::vector<BasicBlock*> Roots;
|
||||
std::vector<BlockT *> Roots;
|
||||
const bool IsPostDominators;
|
||||
|
||||
public:
|
||||
DominanceFrontierBase(char &ID, bool isPostDom)
|
||||
: FunctionPass(ID), IsPostDominators(isPostDom) {}
|
||||
DominanceFrontierBase(bool isPostDom) : IsPostDominators(isPostDom) {}
|
||||
|
||||
/// getRoots - Return the root blocks of the current CFG. This may include
|
||||
/// multiple blocks if we are computing post dominators. For forward
|
||||
/// dominators, this will always be a single block (the entry node).
|
||||
///
|
||||
inline const std::vector<BasicBlock*> &getRoots() const { return Roots; }
|
||||
inline const std::vector<BlockT *> &getRoots() const {
|
||||
return Roots;
|
||||
}
|
||||
|
||||
BlockT *getRoot() const {
|
||||
assert(Roots.size() == 1 && "Should always have entry node!");
|
||||
return Roots[0];
|
||||
}
|
||||
|
||||
/// isPostDominator - Returns true if analysis based of postdoms
|
||||
///
|
||||
bool isPostDominator() const { return IsPostDominators; }
|
||||
bool isPostDominator() const {
|
||||
return IsPostDominators;
|
||||
}
|
||||
|
||||
virtual void releaseMemory() { Frontiers.clear(); }
|
||||
void releaseMemory() {
|
||||
Frontiers.clear();
|
||||
}
|
||||
|
||||
// Accessor interface:
|
||||
typedef DomSetMapType::iterator iterator;
|
||||
typedef DomSetMapType::const_iterator const_iterator;
|
||||
iterator begin() { return Frontiers.begin(); }
|
||||
typedef typename DomSetMapType::iterator iterator;
|
||||
typedef typename DomSetMapType::const_iterator const_iterator;
|
||||
iterator begin() { return Frontiers.begin(); }
|
||||
const_iterator begin() const { return Frontiers.begin(); }
|
||||
iterator end() { return Frontiers.end(); }
|
||||
const_iterator end() const { return Frontiers.end(); }
|
||||
iterator find(BasicBlock *B) { return Frontiers.find(B); }
|
||||
const_iterator find(BasicBlock *B) const { return Frontiers.find(B); }
|
||||
iterator end() { return Frontiers.end(); }
|
||||
const_iterator end() const { return Frontiers.end(); }
|
||||
iterator find(BlockT *B) { return Frontiers.find(B); }
|
||||
const_iterator find(BlockT *B) const { return Frontiers.find(B); }
|
||||
|
||||
iterator addBasicBlock(BasicBlock *BB, const DomSetType &frontier) {
|
||||
iterator addBasicBlock(BlockT *BB, const DomSetType &frontier) {
|
||||
assert(find(BB) == end() && "Block already in DominanceFrontier!");
|
||||
return Frontiers.insert(std::make_pair(BB, frontier)).first;
|
||||
}
|
||||
|
||||
/// removeBlock - Remove basic block BB's frontier.
|
||||
void removeBlock(BasicBlock *BB) {
|
||||
assert(find(BB) != end() && "Block is not in DominanceFrontier!");
|
||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
I->second.erase(BB);
|
||||
Frontiers.erase(BB);
|
||||
}
|
||||
void removeBlock(BlockT *BB);
|
||||
|
||||
void addToFrontier(iterator I, BasicBlock *Node) {
|
||||
assert(I != end() && "BB is not in DominanceFrontier!");
|
||||
I->second.insert(Node);
|
||||
}
|
||||
void addToFrontier(iterator I, BlockT *Node);
|
||||
|
||||
void removeFromFrontier(iterator I, BasicBlock *Node) {
|
||||
assert(I != end() && "BB is not in DominanceFrontier!");
|
||||
assert(I->second.count(Node) && "Node is not in DominanceFrontier of BB");
|
||||
I->second.erase(Node);
|
||||
}
|
||||
void removeFromFrontier(iterator I, BlockT *Node);
|
||||
|
||||
/// compareDomSet - Return false if two domsets match. Otherwise
|
||||
/// return true;
|
||||
bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const {
|
||||
std::set<BasicBlock *> tmpSet;
|
||||
for (DomSetType::const_iterator I = DS2.begin(),
|
||||
E = DS2.end(); I != E; ++I)
|
||||
tmpSet.insert(*I);
|
||||
|
||||
for (DomSetType::const_iterator I = DS1.begin(),
|
||||
E = DS1.end(); I != E; ) {
|
||||
BasicBlock *Node = *I++;
|
||||
|
||||
if (tmpSet.erase(Node) == 0)
|
||||
// Node is in DS1 but not in DS2.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!tmpSet.empty())
|
||||
// There are nodes that are in DS2 but not in DS1.
|
||||
return true;
|
||||
|
||||
// DS1 and DS2 matches.
|
||||
return false;
|
||||
}
|
||||
bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const;
|
||||
|
||||
/// compare - Return true if the other dominance frontier base matches
|
||||
/// this dominance frontier base. Otherwise return false.
|
||||
bool compare(DominanceFrontierBase &Other) const {
|
||||
DomSetMapType tmpFrontiers;
|
||||
for (DomSetMapType::const_iterator I = Other.begin(),
|
||||
E = Other.end(); I != E; ++I)
|
||||
tmpFrontiers.insert(std::make_pair(I->first, I->second));
|
||||
|
||||
for (DomSetMapType::iterator I = tmpFrontiers.begin(),
|
||||
E = tmpFrontiers.end(); I != E; ) {
|
||||
BasicBlock *Node = I->first;
|
||||
const_iterator DFI = find(Node);
|
||||
if (DFI == end())
|
||||
return true;
|
||||
|
||||
if (compareDomSet(I->second, DFI->second))
|
||||
return true;
|
||||
|
||||
++I;
|
||||
tmpFrontiers.erase(Node);
|
||||
}
|
||||
|
||||
if (!tmpFrontiers.empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
bool compare(DominanceFrontierBase<BlockT> &Other) const;
|
||||
|
||||
/// print - Convert to human readable form
|
||||
///
|
||||
virtual void print(raw_ostream &OS, const Module* = 0) const;
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// dump - Dump the dominance frontier to dbgs().
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
|
||||
//===-------------------------------------
|
||||
/// DominanceFrontier Class - Concrete subclass of DominanceFrontierBase that is
|
||||
/// used to compute a forward dominator frontiers.
|
||||
///
|
||||
class DominanceFrontier : public DominanceFrontierBase {
|
||||
virtual void anchor();
|
||||
template <class BlockT>
|
||||
class ForwardDominanceFrontierBase : public DominanceFrontierBase<BlockT> {
|
||||
private:
|
||||
typedef GraphTraits<BlockT *> BlockTraits;
|
||||
|
||||
public:
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
DominanceFrontier() :
|
||||
DominanceFrontierBase(ID, false) {
|
||||
initializeDominanceFrontierPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
typedef DominatorTreeBase<BlockT> DomTreeT;
|
||||
typedef DomTreeNodeBase<BlockT> DomTreeNodeT;
|
||||
typedef typename DominanceFrontierBase<BlockT>::DomSetType DomSetType;
|
||||
|
||||
BasicBlock *getRoot() const {
|
||||
assert(Roots.size() == 1 && "Should always have entry node!");
|
||||
return Roots[0];
|
||||
ForwardDominanceFrontierBase() : DominanceFrontierBase<BlockT>(false) {}
|
||||
|
||||
void analyze(DomTreeT &DT) {
|
||||
this->Roots = DT.getRoots();
|
||||
assert(this->Roots.size() == 1 &&
|
||||
"Only one entry block for forward domfronts!");
|
||||
calculate(DT, DT[this->Roots[0]]);
|
||||
}
|
||||
|
||||
virtual bool runOnFunction(Function &) {
|
||||
Frontiers.clear();
|
||||
DominatorTree &DT = getAnalysis<DominatorTree>();
|
||||
Roots = DT.getRoots();
|
||||
assert(Roots.size() == 1 && "Only one entry block for forward domfronts!");
|
||||
calculate(DT, DT[Roots[0]]);
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<DominatorTree>();
|
||||
}
|
||||
|
||||
const DomSetType &calculate(const DominatorTree &DT,
|
||||
const DomTreeNode *Node);
|
||||
const DomSetType &calculate(const DomTreeT &DT, const DomTreeNodeT *Node);
|
||||
};
|
||||
|
||||
class DominanceFrontier : public FunctionPass {
|
||||
ForwardDominanceFrontierBase<BasicBlock> Base;
|
||||
|
||||
public:
|
||||
typedef DominatorTreeBase<BasicBlock> DomTreeT;
|
||||
typedef DomTreeNodeBase<BasicBlock> DomTreeNodeT;
|
||||
typedef DominanceFrontierBase<BasicBlock>::DomSetType DomSetType;
|
||||
typedef DominanceFrontierBase<BasicBlock>::iterator iterator;
|
||||
typedef DominanceFrontierBase<BasicBlock>::const_iterator const_iterator;
|
||||
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
|
||||
DominanceFrontier();
|
||||
|
||||
ForwardDominanceFrontierBase<BasicBlock> &getBase() { return Base; }
|
||||
|
||||
inline const std::vector<BasicBlock *> &getRoots() const {
|
||||
return Base.getRoots();
|
||||
}
|
||||
|
||||
BasicBlock *getRoot() const { return Base.getRoot(); }
|
||||
|
||||
bool isPostDominator() const { return Base.isPostDominator(); }
|
||||
|
||||
iterator begin() { return Base.begin(); }
|
||||
|
||||
const_iterator begin() const { return Base.begin(); }
|
||||
|
||||
iterator end() { return Base.end(); }
|
||||
|
||||
const_iterator end() const { return Base.end(); }
|
||||
|
||||
iterator find(BasicBlock *B) { return Base.find(B); }
|
||||
|
||||
const_iterator find(BasicBlock *B) const { return Base.find(B); }
|
||||
|
||||
iterator addBasicBlock(BasicBlock *BB, const DomSetType &frontier) {
|
||||
return Base.addBasicBlock(BB, frontier);
|
||||
}
|
||||
|
||||
void removeBlock(BasicBlock *BB) { return Base.removeBlock(BB); }
|
||||
|
||||
void addToFrontier(iterator I, BasicBlock *Node) {
|
||||
return Base.addToFrontier(I, Node);
|
||||
}
|
||||
|
||||
void removeFromFrontier(iterator I, BasicBlock *Node) {
|
||||
return Base.removeFromFrontier(I, Node);
|
||||
}
|
||||
|
||||
bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const {
|
||||
return Base.compareDomSet(DS1, DS2);
|
||||
}
|
||||
|
||||
bool compare(DominanceFrontierBase<BasicBlock> &Other) const {
|
||||
return Base.compare(Other);
|
||||
}
|
||||
|
||||
void releaseMemory() override;
|
||||
|
||||
bool runOnFunction(Function &) override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
void print(raw_ostream &OS, const Module * = nullptr) const override;
|
||||
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
EXTERN_TEMPLATE_INSTANTIATION(class DominanceFrontierBase<BasicBlock>);
|
||||
EXTERN_TEMPLATE_INSTANTIATION(class ForwardDominanceFrontierBase<BasicBlock>);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
228
contrib/llvm/include/llvm/Analysis/DominanceFrontierImpl.h
Normal file
228
contrib/llvm/include/llvm/Analysis/DominanceFrontierImpl.h
Normal file
@ -0,0 +1,228 @@
|
||||
//===- llvm/Analysis/DominanceFrontier.h - Dominator Frontiers --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the generic implementation of the DominanceFrontier class, which
|
||||
// calculate and holds the dominance frontier for a function for.
|
||||
//
|
||||
// This should be considered deprecated, don't add any more uses of this data
|
||||
// structure.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DOMINANCEFRONTIER_IMPL_H
|
||||
#define LLVM_ANALYSIS_DOMINANCEFRONTIER_IMPL_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace {
|
||||
template <class BlockT>
|
||||
class DFCalculateWorkObject {
|
||||
public:
|
||||
typedef DomTreeNodeBase<BlockT> DomTreeNodeT;
|
||||
|
||||
DFCalculateWorkObject(BlockT *B, BlockT *P, const DomTreeNodeT *N,
|
||||
const DomTreeNodeT *PN)
|
||||
: currentBB(B), parentBB(P), Node(N), parentNode(PN) {}
|
||||
BlockT *currentBB;
|
||||
BlockT *parentBB;
|
||||
const DomTreeNodeT *Node;
|
||||
const DomTreeNodeT *parentNode;
|
||||
};
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
void DominanceFrontierBase<BlockT>::removeBlock(BlockT *BB) {
|
||||
assert(find(BB) != end() && "Block is not in DominanceFrontier!");
|
||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
I->second.erase(BB);
|
||||
Frontiers.erase(BB);
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
void DominanceFrontierBase<BlockT>::addToFrontier(iterator I,
|
||||
BlockT *Node) {
|
||||
assert(I != end() && "BB is not in DominanceFrontier!");
|
||||
assert(I->second.count(Node) && "Node is not in DominanceFrontier of BB");
|
||||
I->second.erase(Node);
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
void DominanceFrontierBase<BlockT>::removeFromFrontier(iterator I,
|
||||
BlockT *Node) {
|
||||
assert(I != end() && "BB is not in DominanceFrontier!");
|
||||
assert(I->second.count(Node) && "Node is not in DominanceFrontier of BB");
|
||||
I->second.erase(Node);
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
bool DominanceFrontierBase<BlockT>::compareDomSet(DomSetType &DS1,
|
||||
const DomSetType &DS2) const {
|
||||
std::set<BlockT *> tmpSet;
|
||||
for (BlockT *BB : DS2)
|
||||
tmpSet.insert(BB);
|
||||
|
||||
for (typename DomSetType::const_iterator I = DS1.begin(), E = DS1.end();
|
||||
I != E;) {
|
||||
BlockT *Node = *I++;
|
||||
|
||||
if (tmpSet.erase(Node) == 0)
|
||||
// Node is in DS1 but tnot in DS2.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!tmpSet.empty()) {
|
||||
// There are nodes that are in DS2 but not in DS1.
|
||||
return true;
|
||||
}
|
||||
|
||||
// DS1 and DS2 matches.
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
bool DominanceFrontierBase<BlockT>::compare(
|
||||
DominanceFrontierBase<BlockT> &Other) const {
|
||||
DomSetMapType tmpFrontiers;
|
||||
for (typename DomSetMapType::const_iterator I = Other.begin(),
|
||||
E = Other.end();
|
||||
I != E; ++I)
|
||||
tmpFrontiers.insert(std::make_pair(I->first, I->second));
|
||||
|
||||
for (typename DomSetMapType::iterator I = tmpFrontiers.begin(),
|
||||
E = tmpFrontiers.end();
|
||||
I != E;) {
|
||||
BlockT *Node = I->first;
|
||||
const_iterator DFI = find(Node);
|
||||
if (DFI == end())
|
||||
return true;
|
||||
|
||||
if (compareDomSet(I->second, DFI->second))
|
||||
return true;
|
||||
|
||||
++I;
|
||||
tmpFrontiers.erase(Node);
|
||||
}
|
||||
|
||||
if (!tmpFrontiers.empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
void DominanceFrontierBase<BlockT>::print(raw_ostream &OS) const {
|
||||
for (const_iterator I = begin(), E = end(); I != E; ++I) {
|
||||
OS << " DomFrontier for BB ";
|
||||
if (I->first)
|
||||
I->first->printAsOperand(OS, false);
|
||||
else
|
||||
OS << " <<exit node>>";
|
||||
OS << " is:\t";
|
||||
|
||||
const std::set<BlockT *> &BBs = I->second;
|
||||
|
||||
for (const BlockT *BB : BBs) {
|
||||
OS << ' ';
|
||||
if (BB)
|
||||
BB->printAsOperand(OS, false);
|
||||
else
|
||||
OS << "<<exit node>>";
|
||||
}
|
||||
OS << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
template <class BlockT>
|
||||
void DominanceFrontierBase<BlockT>::dump() const {
|
||||
print(dbgs());
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class BlockT>
|
||||
const typename ForwardDominanceFrontierBase<BlockT>::DomSetType &
|
||||
ForwardDominanceFrontierBase<BlockT>::calculate(const DomTreeT &DT,
|
||||
const DomTreeNodeT *Node) {
|
||||
BlockT *BB = Node->getBlock();
|
||||
DomSetType *Result = nullptr;
|
||||
|
||||
std::vector<DFCalculateWorkObject<BlockT>> workList;
|
||||
SmallPtrSet<BlockT *, 32> visited;
|
||||
|
||||
workList.push_back(DFCalculateWorkObject<BlockT>(BB, nullptr, Node, nullptr));
|
||||
do {
|
||||
DFCalculateWorkObject<BlockT> *currentW = &workList.back();
|
||||
assert(currentW && "Missing work object.");
|
||||
|
||||
BlockT *currentBB = currentW->currentBB;
|
||||
BlockT *parentBB = currentW->parentBB;
|
||||
const DomTreeNodeT *currentNode = currentW->Node;
|
||||
const DomTreeNodeT *parentNode = currentW->parentNode;
|
||||
assert(currentBB && "Invalid work object. Missing current Basic Block");
|
||||
assert(currentNode && "Invalid work object. Missing current Node");
|
||||
DomSetType &S = this->Frontiers[currentBB];
|
||||
|
||||
// Visit each block only once.
|
||||
if (visited.count(currentBB) == 0) {
|
||||
visited.insert(currentBB);
|
||||
|
||||
// Loop over CFG successors to calculate DFlocal[currentNode]
|
||||
for (auto SI = BlockTraits::child_begin(currentBB),
|
||||
SE = BlockTraits::child_end(currentBB);
|
||||
SI != SE; ++SI) {
|
||||
// Does Node immediately dominate this successor?
|
||||
if (DT[*SI]->getIDom() != currentNode)
|
||||
S.insert(*SI);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, S is DFlocal. Now we union in DFup's of our children...
|
||||
// Loop through and visit the nodes that Node immediately dominates (Node's
|
||||
// children in the IDomTree)
|
||||
bool visitChild = false;
|
||||
for (typename DomTreeNodeT::const_iterator NI = currentNode->begin(),
|
||||
NE = currentNode->end();
|
||||
NI != NE; ++NI) {
|
||||
DomTreeNodeT *IDominee = *NI;
|
||||
BlockT *childBB = IDominee->getBlock();
|
||||
if (visited.count(childBB) == 0) {
|
||||
workList.push_back(DFCalculateWorkObject<BlockT>(
|
||||
childBB, currentBB, IDominee, currentNode));
|
||||
visitChild = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If all children are visited or there is any child then pop this block
|
||||
// from the workList.
|
||||
if (!visitChild) {
|
||||
if (!parentBB) {
|
||||
Result = &S;
|
||||
break;
|
||||
}
|
||||
|
||||
typename DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end();
|
||||
DomSetType &parentSet = this->Frontiers[parentBB];
|
||||
for (; CDFI != CDFE; ++CDFI) {
|
||||
if (!DT.properlyDominates(parentNode, DT[*CDFI]))
|
||||
parentSet.insert(*CDFI);
|
||||
}
|
||||
workList.pop_back();
|
||||
}
|
||||
|
||||
} while (!workList.empty());
|
||||
|
||||
return *Result;
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -39,7 +39,7 @@ public:
|
||||
/// passed in, then the types are printed symbolically if possible, using the
|
||||
/// symbol table from the module.
|
||||
///
|
||||
void print(raw_ostream &o, const Module *M) const;
|
||||
void print(raw_ostream &o, const Module *M) const override;
|
||||
|
||||
private:
|
||||
/// IncorporateType - Incorporate one type and all of its subtypes into the
|
||||
@ -53,10 +53,10 @@ private:
|
||||
|
||||
public:
|
||||
/// run - This incorporates all types used by the specified module
|
||||
bool runOnModule(Module &M);
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
/// getAnalysisUsage - We do not modify anything.
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "llvm/Analysis/LoopPass.h"
|
||||
#include "llvm/Analysis/ScalarEvolutionNormalization.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -86,7 +86,7 @@ private:
|
||||
|
||||
/// Deleted - Implementation of CallbackVH virtual function to
|
||||
/// receive notification when the User is deleted.
|
||||
virtual void deleted();
|
||||
void deleted() override;
|
||||
};
|
||||
|
||||
template<> struct ilist_traits<IVStrideUse>
|
||||
@ -122,18 +122,18 @@ class IVUsers : public LoopPass {
|
||||
LoopInfo *LI;
|
||||
DominatorTree *DT;
|
||||
ScalarEvolution *SE;
|
||||
DataLayout *TD;
|
||||
const DataLayout *DL;
|
||||
SmallPtrSet<Instruction*,16> Processed;
|
||||
|
||||
/// IVUses - A list of all tracked IV uses of induction variable expressions
|
||||
/// we are interested in.
|
||||
ilist<IVStrideUse> IVUses;
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
virtual bool runOnLoop(Loop *L, LPPassManager &LPM);
|
||||
bool runOnLoop(Loop *L, LPPassManager &LPM) override;
|
||||
|
||||
virtual void releaseMemory();
|
||||
void releaseMemory() override;
|
||||
|
||||
public:
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
@ -169,7 +169,7 @@ public:
|
||||
return Processed.count(Inst);
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const Module* = 0) const;
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override;
|
||||
|
||||
/// dump - This method is used for debugging.
|
||||
void dump() const;
|
||||
|
@ -99,7 +99,6 @@ public:
|
||||
|
||||
/// \brief Cost analyzer used by inliner.
|
||||
class InlineCostAnalysis : public CallGraphSCCPass {
|
||||
const DataLayout *TD;
|
||||
const TargetTransformInfo *TTI;
|
||||
|
||||
public:
|
||||
@ -109,8 +108,8 @@ public:
|
||||
~InlineCostAnalysis();
|
||||
|
||||
// Pass interface implementation.
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
bool runOnSCC(CallGraphSCC &SCC);
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnSCC(CallGraphSCC &SCC) override;
|
||||
|
||||
/// \brief Get an InlineCost object representing the cost of inlining this
|
||||
/// callsite.
|
||||
|
@ -48,160 +48,166 @@ namespace llvm {
|
||||
/// SimplifyAddInst - Given operands for an Add, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifySubInst - Given operands for a Sub, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// Given operands for an FAdd, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// Given operands for an FSub, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// Given operands for an FMul, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyMulInst - Given operands for a Mul, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifySDivInst - Given operands for an SDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyFDivInst - Given operands for an FDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifySRemInst - Given operands for an SRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyURemInst - Given operands for a URem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyFRemInst - Given operands for an FRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyShlInst - Given operands for a Shl, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyLShrInst - Given operands for a LShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyAShrInst - Given operands for a AShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyAndInst - Given operands for an And, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyOrInst - Given operands for an Or, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyXorInst - Given operands for a Xor, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
|
||||
/// can fold the result. If not, this returns null.
|
||||
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||
ArrayRef<unsigned> Idxs,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyTruncInst - Given operands for an TruncInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
//=== Helper functions for higher up the class hierarchy.
|
||||
|
||||
@ -209,40 +215,40 @@ namespace llvm {
|
||||
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// \brief Given a function and iterators over arguments, see if we can fold
|
||||
/// the result.
|
||||
///
|
||||
/// If this call could not be simplified returns null.
|
||||
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
||||
User::op_iterator ArgEnd, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
User::op_iterator ArgEnd, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// \brief Given a function and set of arguments, see if we can fold the
|
||||
/// result.
|
||||
///
|
||||
/// If this call could not be simplified returns null.
|
||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// SimplifyInstruction - See if we can compute a simplified version of this
|
||||
/// instruction. If not, this returns null.
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
|
||||
/// \brief Replace all uses of 'I' with 'SimpleV' and simplify the uses
|
||||
@ -254,9 +260,9 @@ namespace llvm {
|
||||
///
|
||||
/// The function returns true if any simplifications were performed.
|
||||
bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// \brief Recursively attempt to simplify an instruction.
|
||||
///
|
||||
@ -265,9 +271,9 @@ namespace llvm {
|
||||
/// of the users impacted. It returns true if any simplifications were
|
||||
/// performed.
|
||||
bool recursivelySimplifyInstruction(Instruction *I,
|
||||
const DataLayout *TD = 0,
|
||||
const TargetLibraryInfo *TLI = 0,
|
||||
const DominatorTree *DT = 0);
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -48,9 +48,6 @@ public:
|
||||
Nodes.push_back(Header);
|
||||
}
|
||||
|
||||
inline Interval(const Interval &I) // copy ctor
|
||||
: HeaderNode(I.HeaderNode), Nodes(I.Nodes), Successors(I.Successors) {}
|
||||
|
||||
inline BasicBlock *getHeaderNode() const { return HeaderNode; }
|
||||
|
||||
/// Nodes - The basic blocks in this interval.
|
||||
|
@ -34,8 +34,8 @@
|
||||
#define LLVM_ANALYSIS_INTERVALITERATOR_H
|
||||
|
||||
#include "llvm/Analysis/IntervalPartition.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
@ -34,7 +34,7 @@ namespace llvm {
|
||||
// IntervalPartition - This class builds and holds an "interval partition" for
|
||||
// a function. This partition divides the control flow graph into a set of
|
||||
// maximal intervals, as defined with the properties above. Intuitively, an
|
||||
// interval is a (possibly nonexistent) loop with a "tail" of non looping
|
||||
// interval is a (possibly nonexistent) loop with a "tail" of non-looping
|
||||
// nodes following it.
|
||||
//
|
||||
class IntervalPartition : public FunctionPass {
|
||||
@ -48,12 +48,12 @@ class IntervalPartition : public FunctionPass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
IntervalPartition() : FunctionPass(ID), RootInterval(0) {
|
||||
IntervalPartition() : FunctionPass(ID), RootInterval(nullptr) {
|
||||
initializeIntervalPartitionPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
// run - Calculate the interval partition for this function
|
||||
virtual bool runOnFunction(Function &F);
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
// IntervalPartition ctor - Build a reduced interval partition from an
|
||||
// existing interval graph. This takes an additional boolean parameter to
|
||||
@ -62,7 +62,7 @@ public:
|
||||
IntervalPartition(IntervalPartition &I, bool);
|
||||
|
||||
// print - Show contents in human readable format...
|
||||
virtual void print(raw_ostream &O, const Module* = 0) const;
|
||||
void print(raw_ostream &O, const Module* = nullptr) const override;
|
||||
|
||||
// getRootInterval() - Return the root interval that contains the starting
|
||||
// block of the function.
|
||||
@ -77,11 +77,11 @@ public:
|
||||
// getBlockInterval - Return the interval that a basic block exists in.
|
||||
inline Interval *getBlockInterval(BasicBlock *BB) {
|
||||
IntervalMapTy::iterator I = IntervalMap.find(BB);
|
||||
return I != IntervalMap.end() ? I->second : 0;
|
||||
return I != IntervalMap.end() ? I->second : nullptr;
|
||||
}
|
||||
|
||||
// getAnalysisUsage - Implement the Pass API
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
const std::vector<Interval*> &getIntervals() const { return Intervals; }
|
||||
|
||||
// releaseMemory - Reset state back to before function was analyzed
|
||||
void releaseMemory();
|
||||
void releaseMemory() override;
|
||||
|
||||
private:
|
||||
// addIntervalToPartition - Add an interval to the internal list of intervals,
|
||||
|
60
contrib/llvm/include/llvm/Analysis/JumpInstrTableInfo.h
Normal file
60
contrib/llvm/include/llvm/Analysis/JumpInstrTableInfo.h
Normal file
@ -0,0 +1,60 @@
|
||||
//===-- JumpInstrTableInfo.h: Info for Jump-Instruction Tables --*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Information about jump-instruction tables that have been created by
|
||||
/// JumpInstrTables pass.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H
|
||||
#define LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class FunctionType;
|
||||
|
||||
/// This class stores information about jump-instruction tables created by the
|
||||
/// JumpInstrTables pass (in lib/CodeGen/JumpInstrTables.cpp). Each table is a
|
||||
/// map from a function type to a vector of pairs. The first element of each
|
||||
/// pair is the function that has the jumptable annotation. The second element
|
||||
/// is a function that was declared by JumpInstrTables and used to replace all
|
||||
/// address-taking sites for the original function.
|
||||
///
|
||||
/// The information in this pass is used in AsmPrinter
|
||||
/// (lib/CodeGen/AsmPrinter/AsmPrinter.cpp) to generate the required assembly
|
||||
/// for the jump-instruction tables.
|
||||
class JumpInstrTableInfo : public ImmutablePass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
JumpInstrTableInfo();
|
||||
virtual ~JumpInstrTableInfo();
|
||||
const char *getPassName() const override {
|
||||
return "Jump-Instruction Table Info";
|
||||
}
|
||||
|
||||
typedef std::pair<Function *, Function *> JumpPair;
|
||||
typedef DenseMap<FunctionType *, std::vector<JumpPair> > JumpTables;
|
||||
|
||||
/// Inserts an entry in a table, adding the table if it doesn't exist.
|
||||
void insertEntry(FunctionType *TableFunTy, Function *Target, Function *Jump);
|
||||
|
||||
/// Gets the tables.
|
||||
const JumpTables &getTables() const { return Tables; }
|
||||
|
||||
private:
|
||||
JumpTables Tables;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H */
|
566
contrib/llvm/include/llvm/Analysis/LazyCallGraph.h
Normal file
566
contrib/llvm/include/llvm/Analysis/LazyCallGraph.h
Normal file
@ -0,0 +1,566 @@
|
||||
//===- LazyCallGraph.h - Analysis of a Module's call graph ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// Implements a lazy call graph analysis and related passes for the new pass
|
||||
/// manager.
|
||||
///
|
||||
/// NB: This is *not* a traditional call graph! It is a graph which models both
|
||||
/// the current calls and potential calls. As a consequence there are many
|
||||
/// edges in this call graph that do not correspond to a 'call' or 'invoke'
|
||||
/// instruction.
|
||||
///
|
||||
/// The primary use cases of this graph analysis is to facilitate iterating
|
||||
/// across the functions of a module in ways that ensure all callees are
|
||||
/// visited prior to a caller (given any SCC constraints), or vice versa. As
|
||||
/// such is it particularly well suited to organizing CGSCC optimizations such
|
||||
/// as inlining, outlining, argument promotion, etc. That is its primary use
|
||||
/// case and motivates the design. It may not be appropriate for other
|
||||
/// purposes. The use graph of functions or some other conservative analysis of
|
||||
/// call instructions may be interesting for optimizations and subsequent
|
||||
/// analyses which don't work in the context of an overly specified
|
||||
/// potential-call-edge graph.
|
||||
///
|
||||
/// To understand the specific rules and nature of this call graph analysis,
|
||||
/// see the documentation of the \c LazyCallGraph below.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LAZY_CALL_GRAPH
|
||||
#define LLVM_ANALYSIS_LAZY_CALL_GRAPH
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <iterator>
|
||||
|
||||
namespace llvm {
|
||||
class ModuleAnalysisManager;
|
||||
class PreservedAnalyses;
|
||||
class raw_ostream;
|
||||
|
||||
/// \brief A lazily constructed view of the call graph of a module.
|
||||
///
|
||||
/// With the edges of this graph, the motivating constraint that we are
|
||||
/// attempting to maintain is that function-local optimization, CGSCC-local
|
||||
/// optimizations, and optimizations transforming a pair of functions connected
|
||||
/// by an edge in the graph, do not invalidate a bottom-up traversal of the SCC
|
||||
/// DAG. That is, no optimizations will delete, remove, or add an edge such
|
||||
/// that functions already visited in a bottom-up order of the SCC DAG are no
|
||||
/// longer valid to have visited, or such that functions not yet visited in
|
||||
/// a bottom-up order of the SCC DAG are not required to have already been
|
||||
/// visited.
|
||||
///
|
||||
/// Within this constraint, the desire is to minimize the merge points of the
|
||||
/// SCC DAG. The greater the fanout of the SCC DAG and the fewer merge points
|
||||
/// in the SCC DAG, the more independence there is in optimizing within it.
|
||||
/// There is a strong desire to enable parallelization of optimizations over
|
||||
/// the call graph, and both limited fanout and merge points will (artificially
|
||||
/// in some cases) limit the scaling of such an effort.
|
||||
///
|
||||
/// To this end, graph represents both direct and any potential resolution to
|
||||
/// an indirect call edge. Another way to think about it is that it represents
|
||||
/// both the direct call edges and any direct call edges that might be formed
|
||||
/// through static optimizations. Specifically, it considers taking the address
|
||||
/// of a function to be an edge in the call graph because this might be
|
||||
/// forwarded to become a direct call by some subsequent function-local
|
||||
/// optimization. The result is that the graph closely follows the use-def
|
||||
/// edges for functions. Walking "up" the graph can be done by looking at all
|
||||
/// of the uses of a function.
|
||||
///
|
||||
/// The roots of the call graph are the external functions and functions
|
||||
/// escaped into global variables. Those functions can be called from outside
|
||||
/// of the module or via unknowable means in the IR -- we may not be able to
|
||||
/// form even a potential call edge from a function body which may dynamically
|
||||
/// load the function and call it.
|
||||
///
|
||||
/// This analysis still requires updates to remain valid after optimizations
|
||||
/// which could potentially change the set of potential callees. The
|
||||
/// constraints it operates under only make the traversal order remain valid.
|
||||
///
|
||||
/// The entire analysis must be re-computed if full interprocedural
|
||||
/// optimizations run at any point. For example, globalopt completely
|
||||
/// invalidates the information in this analysis.
|
||||
///
|
||||
/// FIXME: This class is named LazyCallGraph in a lame attempt to distinguish
|
||||
/// it from the existing CallGraph. At some point, it is expected that this
|
||||
/// will be the only call graph and it will be renamed accordingly.
|
||||
class LazyCallGraph {
|
||||
public:
|
||||
class Node;
|
||||
class SCC;
|
||||
typedef SmallVector<PointerUnion<Function *, Node *>, 4> NodeVectorT;
|
||||
typedef SmallVectorImpl<PointerUnion<Function *, Node *>> NodeVectorImplT;
|
||||
|
||||
/// \brief A lazy iterator used for both the entry nodes and child nodes.
|
||||
///
|
||||
/// When this iterator is dereferenced, if not yet available, a function will
|
||||
/// be scanned for "calls" or uses of functions and its child information
|
||||
/// will be constructed. All of these results are accumulated and cached in
|
||||
/// the graph.
|
||||
class iterator
|
||||
: public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
|
||||
std::forward_iterator_tag, Node> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
LazyCallGraph *G;
|
||||
NodeVectorImplT::iterator E;
|
||||
|
||||
// Build the iterator for a specific position in a node list.
|
||||
iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
|
||||
NodeVectorImplT::iterator E)
|
||||
: iterator_adaptor_base(NI), G(&G), E(E) {
|
||||
while (I != E && I->isNull())
|
||||
++I;
|
||||
}
|
||||
|
||||
public:
|
||||
iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
iterator &operator++() {
|
||||
do {
|
||||
++I;
|
||||
} while (I != E && I->isNull());
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
if (I->is<Node *>())
|
||||
return *I->get<Node *>();
|
||||
|
||||
Function *F = I->get<Function *>();
|
||||
Node &ChildN = G->get(*F);
|
||||
*I = &ChildN;
|
||||
return ChildN;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A node in the call graph.
|
||||
///
|
||||
/// This represents a single node. It's primary roles are to cache the list of
|
||||
/// callees, de-duplicate and provide fast testing of whether a function is
|
||||
/// a callee, and facilitate iteration of child nodes in the graph.
|
||||
class Node {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::SCC;
|
||||
|
||||
LazyCallGraph *G;
|
||||
Function &F;
|
||||
|
||||
// We provide for the DFS numbering and Tarjan walk lowlink numbers to be
|
||||
// stored directly within the node.
|
||||
int DFSNumber;
|
||||
int LowLink;
|
||||
|
||||
mutable NodeVectorT Callees;
|
||||
DenseMap<Function *, size_t> CalleeIndexMap;
|
||||
|
||||
/// \brief Basic constructor implements the scanning of F into Callees and
|
||||
/// CalleeIndexMap.
|
||||
Node(LazyCallGraph &G, Function &F);
|
||||
|
||||
/// \brief Internal helper to insert a callee.
|
||||
void insertEdgeInternal(Function &Callee);
|
||||
|
||||
/// \brief Internal helper to insert a callee.
|
||||
void insertEdgeInternal(Node &CalleeN);
|
||||
|
||||
/// \brief Internal helper to remove a callee from this node.
|
||||
void removeEdgeInternal(Function &Callee);
|
||||
|
||||
public:
|
||||
typedef LazyCallGraph::iterator iterator;
|
||||
|
||||
Function &getFunction() const {
|
||||
return F;
|
||||
};
|
||||
|
||||
iterator begin() const {
|
||||
return iterator(*G, Callees.begin(), Callees.end());
|
||||
}
|
||||
iterator end() const { return iterator(*G, Callees.end(), Callees.end()); }
|
||||
|
||||
/// Equality is defined as address equality.
|
||||
bool operator==(const Node &N) const { return this == &N; }
|
||||
bool operator!=(const Node &N) const { return !operator==(N); }
|
||||
};
|
||||
|
||||
/// \brief An SCC of the call graph.
|
||||
///
|
||||
/// This represents a Strongly Connected Component of the call graph as
|
||||
/// a collection of call graph nodes. While the order of nodes in the SCC is
|
||||
/// stable, it is not any particular order.
|
||||
class SCC {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
LazyCallGraph *G;
|
||||
SmallPtrSet<SCC *, 1> ParentSCCs;
|
||||
SmallVector<Node *, 1> Nodes;
|
||||
|
||||
SCC(LazyCallGraph &G) : G(&G) {}
|
||||
|
||||
void insert(Node &N);
|
||||
|
||||
void
|
||||
internalDFS(SmallVectorImpl<std::pair<Node *, Node::iterator>> &DFSStack,
|
||||
SmallVectorImpl<Node *> &PendingSCCStack, Node *N,
|
||||
SmallVectorImpl<SCC *> &ResultSCCs);
|
||||
|
||||
public:
|
||||
typedef SmallVectorImpl<Node *>::const_iterator iterator;
|
||||
typedef pointee_iterator<SmallPtrSet<SCC *, 1>::const_iterator> parent_iterator;
|
||||
|
||||
iterator begin() const { return Nodes.begin(); }
|
||||
iterator end() const { return Nodes.end(); }
|
||||
|
||||
parent_iterator parent_begin() const { return ParentSCCs.begin(); }
|
||||
parent_iterator parent_end() const { return ParentSCCs.end(); }
|
||||
|
||||
iterator_range<parent_iterator> parents() const {
|
||||
return iterator_range<parent_iterator>(parent_begin(), parent_end());
|
||||
}
|
||||
|
||||
/// \brief Test if this SCC is a parent of \a C.
|
||||
bool isParentOf(const SCC &C) const { return C.isChildOf(*this); }
|
||||
|
||||
/// \brief Test if this SCC is an ancestor of \a C.
|
||||
bool isAncestorOf(const SCC &C) const { return C.isDescendantOf(*this); }
|
||||
|
||||
/// \brief Test if this SCC is a child of \a C.
|
||||
bool isChildOf(const SCC &C) const {
|
||||
return ParentSCCs.count(const_cast<SCC *>(&C));
|
||||
}
|
||||
|
||||
/// \brief Test if this SCC is a descendant of \a C.
|
||||
bool isDescendantOf(const SCC &C) const;
|
||||
|
||||
///@{
|
||||
/// \name Mutation API
|
||||
///
|
||||
/// These methods provide the core API for updating the call graph in the
|
||||
/// presence of a (potentially still in-flight) DFS-found SCCs.
|
||||
///
|
||||
/// Note that these methods sometimes have complex runtimes, so be careful
|
||||
/// how you call them.
|
||||
|
||||
/// \brief Insert an edge from one node in this SCC to another in this SCC.
|
||||
///
|
||||
/// By the definition of an SCC, this does not change the nature or make-up
|
||||
/// of any SCCs.
|
||||
void insertIntraSCCEdge(Node &CallerN, Node &CalleeN);
|
||||
|
||||
/// \brief Insert an edge whose tail is in this SCC and head is in some
|
||||
/// child SCC.
|
||||
///
|
||||
/// There must be an existing path from the caller to the callee. This
|
||||
/// operation is inexpensive and does not change the set of SCCs in the
|
||||
/// graph.
|
||||
void insertOutgoingEdge(Node &CallerN, Node &CalleeN);
|
||||
|
||||
/// \brief Insert an edge whose tail is in a descendant SCC and head is in
|
||||
/// this SCC.
|
||||
///
|
||||
/// There must be an existing path from the callee to the caller in this
|
||||
/// case. NB! This is has the potential to be a very expensive function. It
|
||||
/// inherently forms a cycle in the prior SCC DAG and we have to merge SCCs
|
||||
/// to resolve that cycle. But finding all of the SCCs which participate in
|
||||
/// the cycle can in the worst case require traversing every SCC in the
|
||||
/// graph. Every attempt is made to avoid that, but passes must still
|
||||
/// exercise caution calling this routine repeatedly.
|
||||
///
|
||||
/// FIXME: We could possibly optimize this quite a bit for cases where the
|
||||
/// caller and callee are very nearby in the graph. See comments in the
|
||||
/// implementation for details, but that use case might impact users.
|
||||
SmallVector<SCC *, 1> insertIncomingEdge(Node &CallerN, Node &CalleeN);
|
||||
|
||||
/// \brief Remove an edge whose source is in this SCC and target is *not*.
|
||||
///
|
||||
/// This removes an inter-SCC edge. All inter-SCC edges originating from
|
||||
/// this SCC have been fully explored by any in-flight DFS SCC formation,
|
||||
/// so this is always safe to call once you have the source SCC.
|
||||
///
|
||||
/// This operation does not change the set of SCCs or the members of the
|
||||
/// SCCs and so is very inexpensive. It may change the connectivity graph
|
||||
/// of the SCCs though, so be careful calling this while iterating over
|
||||
/// them.
|
||||
void removeInterSCCEdge(Node &CallerN, Node &CalleeN);
|
||||
|
||||
/// \brief Remove an edge which is entirely within this SCC.
|
||||
///
|
||||
/// Both the \a Caller and the \a Callee must be within this SCC. Removing
|
||||
/// such an edge make break cycles that form this SCC and thus this
|
||||
/// operation may change the SCC graph significantly. In particular, this
|
||||
/// operation will re-form new SCCs based on the remaining connectivity of
|
||||
/// the graph. The following invariants are guaranteed to hold after
|
||||
/// calling this method:
|
||||
///
|
||||
/// 1) This SCC is still an SCC in the graph.
|
||||
/// 2) This SCC will be the parent of any new SCCs. Thus, this SCC is
|
||||
/// preserved as the root of any new SCC directed graph formed.
|
||||
/// 3) No SCC other than this SCC has its member set changed (this is
|
||||
/// inherent in the definition of removing such an edge).
|
||||
/// 4) All of the parent links of the SCC graph will be updated to reflect
|
||||
/// the new SCC structure.
|
||||
/// 5) All SCCs formed out of this SCC, excluding this SCC, will be
|
||||
/// returned in a vector.
|
||||
/// 6) The order of the SCCs in the vector will be a valid postorder
|
||||
/// traversal of the new SCCs.
|
||||
///
|
||||
/// These invariants are very important to ensure that we can build
|
||||
/// optimization pipeliens on top of the CGSCC pass manager which
|
||||
/// intelligently update the SCC graph without invalidating other parts of
|
||||
/// the SCC graph.
|
||||
///
|
||||
/// The runtime complexity of this method is, in the worst case, O(V+E)
|
||||
/// where V is the number of nodes in this SCC and E is the number of edges
|
||||
/// leaving the nodes in this SCC. Note that E includes both edges within
|
||||
/// this SCC and edges from this SCC to child SCCs. Some effort has been
|
||||
/// made to minimize the overhead of common cases such as self-edges and
|
||||
/// edge removals which result in a spanning tree with no more cycles.
|
||||
SmallVector<SCC *, 1> removeIntraSCCEdge(Node &CallerN, Node &CalleeN);
|
||||
|
||||
///@}
|
||||
};
|
||||
|
||||
/// \brief A post-order depth-first SCC iterator over the call graph.
|
||||
///
|
||||
/// This iterator triggers the Tarjan DFS-based formation of the SCC DAG for
|
||||
/// the call graph, walking it lazily in depth-first post-order. That is, it
|
||||
/// always visits SCCs for a callee prior to visiting the SCC for a caller
|
||||
/// (when they are in different SCCs).
|
||||
class postorder_scc_iterator
|
||||
: public iterator_facade_base<postorder_scc_iterator,
|
||||
std::forward_iterator_tag, SCC> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
/// \brief Nonce type to select the constructor for the end iterator.
|
||||
struct IsAtEndT {};
|
||||
|
||||
LazyCallGraph *G;
|
||||
SCC *C;
|
||||
|
||||
// Build the begin iterator for a node.
|
||||
postorder_scc_iterator(LazyCallGraph &G) : G(&G) {
|
||||
C = G.getNextSCCInPostOrder();
|
||||
}
|
||||
|
||||
// Build the end iterator for a node. This is selected purely by overload.
|
||||
postorder_scc_iterator(LazyCallGraph &G, IsAtEndT /*Nonce*/)
|
||||
: G(&G), C(nullptr) {}
|
||||
|
||||
public:
|
||||
bool operator==(const postorder_scc_iterator &Arg) const {
|
||||
return G == Arg.G && C == Arg.C;
|
||||
}
|
||||
|
||||
reference operator*() const { return *C; }
|
||||
|
||||
using iterator_facade_base::operator++;
|
||||
postorder_scc_iterator &operator++() {
|
||||
C = G->getNextSCCInPostOrder();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Construct a graph for the given module.
|
||||
///
|
||||
/// This sets up the graph and computes all of the entry points of the graph.
|
||||
/// No function definitions are scanned until their nodes in the graph are
|
||||
/// requested during traversal.
|
||||
LazyCallGraph(Module &M);
|
||||
|
||||
LazyCallGraph(LazyCallGraph &&G);
|
||||
LazyCallGraph &operator=(LazyCallGraph &&RHS);
|
||||
|
||||
iterator begin() {
|
||||
return iterator(*this, EntryNodes.begin(), EntryNodes.end());
|
||||
}
|
||||
iterator end() { return iterator(*this, EntryNodes.end(), EntryNodes.end()); }
|
||||
|
||||
postorder_scc_iterator postorder_scc_begin() {
|
||||
return postorder_scc_iterator(*this);
|
||||
}
|
||||
postorder_scc_iterator postorder_scc_end() {
|
||||
return postorder_scc_iterator(*this, postorder_scc_iterator::IsAtEndT());
|
||||
}
|
||||
|
||||
iterator_range<postorder_scc_iterator> postorder_sccs() {
|
||||
return iterator_range<postorder_scc_iterator>(postorder_scc_begin(),
|
||||
postorder_scc_end());
|
||||
}
|
||||
|
||||
/// \brief Lookup a function in the graph which has already been scanned and
|
||||
/// added.
|
||||
Node *lookup(const Function &F) const { return NodeMap.lookup(&F); }
|
||||
|
||||
/// \brief Lookup a function's SCC in the graph.
|
||||
///
|
||||
/// \returns null if the function hasn't been assigned an SCC via the SCC
|
||||
/// iterator walk.
|
||||
SCC *lookupSCC(Node &N) const { return SCCMap.lookup(&N); }
|
||||
|
||||
/// \brief Get a graph node for a given function, scanning it to populate the
|
||||
/// graph data as necessary.
|
||||
Node &get(Function &F) {
|
||||
Node *&N = NodeMap[&F];
|
||||
if (N)
|
||||
return *N;
|
||||
|
||||
return insertInto(F, N);
|
||||
}
|
||||
|
||||
///@{
|
||||
/// \name Pre-SCC Mutation API
|
||||
///
|
||||
/// These methods are only valid to call prior to forming any SCCs for this
|
||||
/// call graph. They can be used to update the core node-graph during
|
||||
/// a node-based inorder traversal that precedes any SCC-based traversal.
|
||||
///
|
||||
/// Once you begin manipulating a call graph's SCCs, you must perform all
|
||||
/// mutation of the graph via the SCC methods.
|
||||
|
||||
/// \brief Update the call graph after inserting a new edge.
|
||||
void insertEdge(Node &Caller, Function &Callee);
|
||||
|
||||
/// \brief Update the call graph after inserting a new edge.
|
||||
void insertEdge(Function &Caller, Function &Callee) {
|
||||
return insertEdge(get(Caller), Callee);
|
||||
}
|
||||
|
||||
/// \brief Update the call graph after deleting an edge.
|
||||
void removeEdge(Node &Caller, Function &Callee);
|
||||
|
||||
/// \brief Update the call graph after deleting an edge.
|
||||
void removeEdge(Function &Caller, Function &Callee) {
|
||||
return removeEdge(get(Caller), Callee);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/// \brief Allocator that holds all the call graph nodes.
|
||||
SpecificBumpPtrAllocator<Node> BPA;
|
||||
|
||||
/// \brief Maps function->node for fast lookup.
|
||||
DenseMap<const Function *, Node *> NodeMap;
|
||||
|
||||
/// \brief The entry nodes to the graph.
|
||||
///
|
||||
/// These nodes are reachable through "external" means. Put another way, they
|
||||
/// escape at the module scope.
|
||||
NodeVectorT EntryNodes;
|
||||
|
||||
/// \brief Map of the entry nodes in the graph to their indices in
|
||||
/// \c EntryNodes.
|
||||
DenseMap<Function *, size_t> EntryIndexMap;
|
||||
|
||||
/// \brief Allocator that holds all the call graph SCCs.
|
||||
SpecificBumpPtrAllocator<SCC> SCCBPA;
|
||||
|
||||
/// \brief Maps Function -> SCC for fast lookup.
|
||||
DenseMap<Node *, SCC *> SCCMap;
|
||||
|
||||
/// \brief The leaf SCCs of the graph.
|
||||
///
|
||||
/// These are all of the SCCs which have no children.
|
||||
SmallVector<SCC *, 4> LeafSCCs;
|
||||
|
||||
/// \brief Stack of nodes in the DFS walk.
|
||||
SmallVector<std::pair<Node *, iterator>, 4> DFSStack;
|
||||
|
||||
/// \brief Set of entry nodes not-yet-processed into SCCs.
|
||||
SmallVector<Function *, 4> SCCEntryNodes;
|
||||
|
||||
/// \brief Stack of nodes the DFS has walked but not yet put into a SCC.
|
||||
SmallVector<Node *, 4> PendingSCCStack;
|
||||
|
||||
/// \brief Counter for the next DFS number to assign.
|
||||
int NextDFSNumber;
|
||||
|
||||
/// \brief Helper to insert a new function, with an already looked-up entry in
|
||||
/// the NodeMap.
|
||||
Node &insertInto(Function &F, Node *&MappedN);
|
||||
|
||||
/// \brief Helper to update pointers back to the graph object during moves.
|
||||
void updateGraphPtrs();
|
||||
|
||||
/// \brief Helper to form a new SCC out of the top of a DFSStack-like
|
||||
/// structure.
|
||||
SCC *formSCC(Node *RootN, SmallVectorImpl<Node *> &NodeStack);
|
||||
|
||||
/// \brief Retrieve the next node in the post-order SCC walk of the call graph.
|
||||
SCC *getNextSCCInPostOrder();
|
||||
};
|
||||
|
||||
// Provide GraphTraits specializations for call graphs.
|
||||
template <> struct GraphTraits<LazyCallGraph::Node *> {
|
||||
typedef LazyCallGraph::Node NodeType;
|
||||
typedef LazyCallGraph::iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(NodeType *N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
template <> struct GraphTraits<LazyCallGraph *> {
|
||||
typedef LazyCallGraph::Node NodeType;
|
||||
typedef LazyCallGraph::iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(NodeType *N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
/// \brief An analysis pass which computes the call graph for a module.
|
||||
class LazyCallGraphAnalysis {
|
||||
public:
|
||||
/// \brief Inform generic clients of the result type.
|
||||
typedef LazyCallGraph Result;
|
||||
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Compute the \c LazyCallGraph for a the module \c M.
|
||||
///
|
||||
/// This just builds the set of entry points to the call graph. The rest is
|
||||
/// built lazily as it is walked.
|
||||
LazyCallGraph run(Module *M) { return LazyCallGraph(*M); }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
};
|
||||
|
||||
/// \brief A pass which prints the call graph to a \c raw_ostream.
|
||||
///
|
||||
/// This is primarily useful for testing the analysis.
|
||||
class LazyCallGraphPrinterPass {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit LazyCallGraphPrinterPass(raw_ostream &OS);
|
||||
|
||||
PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM);
|
||||
|
||||
static StringRef name() { return "LazyCallGraphPrinterPass"; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -26,17 +26,17 @@ namespace llvm {
|
||||
/// LazyValueInfo - This pass computes, caches, and vends lazy value constraint
|
||||
/// information.
|
||||
class LazyValueInfo : public FunctionPass {
|
||||
class DataLayout *TD;
|
||||
const DataLayout *DL;
|
||||
class TargetLibraryInfo *TLI;
|
||||
void *PImpl;
|
||||
LazyValueInfo(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
||||
public:
|
||||
static char ID;
|
||||
LazyValueInfo() : FunctionPass(ID), PImpl(0) {
|
||||
LazyValueInfo() : FunctionPass(ID), PImpl(nullptr) {
|
||||
initializeLazyValueInfoPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
~LazyValueInfo() { assert(PImpl == 0 && "releaseMemory not called"); }
|
||||
~LazyValueInfo() { assert(!PImpl && "releaseMemory not called"); }
|
||||
|
||||
/// Tristate - This is used to return true/false/dunno results.
|
||||
enum Tristate {
|
||||
@ -69,10 +69,10 @@ public:
|
||||
void eraseBlock(BasicBlock *BB);
|
||||
|
||||
// Implementation boilerplate.
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
virtual void releaseMemory();
|
||||
virtual bool runOnFunction(Function &F);
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
void releaseMemory() override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -27,7 +27,7 @@ namespace llvm {
|
||||
|
||||
LibCallInfo *LCI;
|
||||
|
||||
explicit LibCallAliasAnalysis(LibCallInfo *LC = 0)
|
||||
explicit LibCallAliasAnalysis(LibCallInfo *LC = nullptr)
|
||||
: FunctionPass(ID), LCI(LC) {
|
||||
initializeLibCallAliasAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
@ -38,17 +38,17 @@ namespace llvm {
|
||||
~LibCallAliasAnalysis();
|
||||
|
||||
ModRefResult getModRefInfo(ImmutableCallSite CS,
|
||||
const Location &Loc);
|
||||
|
||||
const Location &Loc) override;
|
||||
|
||||
ModRefResult getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2) {
|
||||
ImmutableCallSite CS2) override {
|
||||
// TODO: Could compare two direct calls against each other if we cared to.
|
||||
return AliasAnalysis::getModRefInfo(CS1, CS2);
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
InitializeAliasAnalysis(this); // set up super class
|
||||
return false;
|
||||
}
|
||||
@ -57,7 +57,7 @@ namespace llvm {
|
||||
/// an analysis interface through multiple inheritance. If needed, it
|
||||
/// should override this to adjust the this pointer as needed for the
|
||||
/// specified pass info.
|
||||
virtual void *getAdjustedAnalysisPointer(const void *PI) {
|
||||
void *getAdjustedAnalysisPointer(const void *PI) override {
|
||||
if (PI == &AliasAnalysis::ID)
|
||||
return (AliasAnalysis*)this;
|
||||
return this;
|
||||
|
@ -27,7 +27,7 @@ namespace llvm {
|
||||
/// standard libm functions. The location that they may be interested in is
|
||||
/// an abstract location that represents errno for the current target. In
|
||||
/// this case, a location for errno is anything such that the predicate
|
||||
/// returns true. On Mac OS/X, this predicate would return true if the
|
||||
/// returns true. On Mac OS X, this predicate would return true if the
|
||||
/// pointer is the result of a call to "__error()".
|
||||
///
|
||||
/// Locations can also be defined in a constant-sensitive way. For example,
|
||||
@ -130,7 +130,7 @@ namespace llvm {
|
||||
mutable const LibCallLocationInfo *Locations;
|
||||
mutable unsigned NumLocations;
|
||||
public:
|
||||
LibCallInfo() : Impl(0), Locations(0), NumLocations(0) {}
|
||||
LibCallInfo() : Impl(nullptr), Locations(nullptr), NumLocations(0) {}
|
||||
virtual ~LibCallInfo();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
|
@ -27,7 +27,8 @@ class MDNode;
|
||||
/// specified pointer, we do a quick local scan of the basic block containing
|
||||
/// ScanFrom, to determine if the address is already accessed.
|
||||
bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
|
||||
unsigned Align, const DataLayout *TD = 0);
|
||||
unsigned Align,
|
||||
const DataLayout *TD = nullptr);
|
||||
|
||||
/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at
|
||||
/// the instruction before ScanFrom) checking to see if we have the value at
|
||||
@ -49,8 +50,8 @@ bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
|
||||
Value *FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB,
|
||||
BasicBlock::iterator &ScanFrom,
|
||||
unsigned MaxInstsToScan = 6,
|
||||
AliasAnalysis *AA = 0,
|
||||
MDNode **TBAATag = 0);
|
||||
AliasAnalysis *AA = nullptr,
|
||||
MDNode **TBAATag = nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,10 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <algorithm>
|
||||
|
||||
@ -53,6 +55,7 @@ class Loop;
|
||||
class MDNode;
|
||||
class PHINode;
|
||||
class raw_ostream;
|
||||
template<class N> class DominatorTreeBase;
|
||||
template<class N, class M> class LoopInfoBase;
|
||||
template<class N, class M> class LoopBase;
|
||||
|
||||
@ -76,7 +79,7 @@ class LoopBase {
|
||||
operator=(const LoopBase<BlockT, LoopT> &) LLVM_DELETED_FUNCTION;
|
||||
public:
|
||||
/// Loop ctor - This creates an empty loop.
|
||||
LoopBase() : ParentLoop(0) {}
|
||||
LoopBase() : ParentLoop(nullptr) {}
|
||||
~LoopBase() {
|
||||
for (size_t i = 0, e = SubLoops.size(); i != e; ++i)
|
||||
delete SubLoops[i];
|
||||
@ -103,7 +106,7 @@ public:
|
||||
///
|
||||
bool contains(const LoopT *L) const {
|
||||
if (L == this) return true;
|
||||
if (L == 0) return false;
|
||||
if (!L) return false;
|
||||
return contains(L->getParentLoop());
|
||||
}
|
||||
|
||||
@ -228,6 +231,18 @@ public:
|
||||
/// A latch block is a block that contains a branch back to the header.
|
||||
BlockT *getLoopLatch() const;
|
||||
|
||||
/// getLoopLatches - Return all loop latch blocks of this loop. A latch block
|
||||
/// is a block that contains a branch back to the header.
|
||||
void getLoopLatches(SmallVectorImpl<BlockT *> &LoopLatches) const {
|
||||
BlockT *H = getHeader();
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
for (typename InvBlockTraits::ChildIteratorType I =
|
||||
InvBlockTraits::child_begin(H),
|
||||
E = InvBlockTraits::child_end(H); I != E; ++I)
|
||||
if (contains(*I))
|
||||
LoopLatches.push_back(*I);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// APIs for updating loop information after changing the CFG
|
||||
//
|
||||
@ -250,7 +265,7 @@ public:
|
||||
/// updates the loop depth of the new child.
|
||||
///
|
||||
void addChildLoop(LoopT *NewChild) {
|
||||
assert(NewChild->ParentLoop == 0 && "NewChild already has a parent!");
|
||||
assert(!NewChild->ParentLoop && "NewChild already has a parent!");
|
||||
NewChild->ParentLoop = static_cast<LoopT *>(this);
|
||||
SubLoops.push_back(NewChild);
|
||||
}
|
||||
@ -263,7 +278,7 @@ public:
|
||||
LoopT *Child = *I;
|
||||
assert(Child->ParentLoop == this && "Child is not a child of this loop!");
|
||||
SubLoops.erase(SubLoops.begin()+(I-begin()));
|
||||
Child->ParentLoop = 0;
|
||||
Child->ParentLoop = nullptr;
|
||||
return Child;
|
||||
}
|
||||
|
||||
@ -318,7 +333,7 @@ public:
|
||||
|
||||
protected:
|
||||
friend class LoopInfoBase<BlockT, LoopT>;
|
||||
explicit LoopBase(BlockT *BB) : ParentLoop(0) {
|
||||
explicit LoopBase(BlockT *BB) : ParentLoop(nullptr) {
|
||||
Blocks.push_back(BB);
|
||||
DenseBlockSet.insert(BB);
|
||||
}
|
||||
@ -357,7 +372,7 @@ public:
|
||||
/// If null, the terminator of the loop preheader is used.
|
||||
///
|
||||
bool makeLoopInvariant(Value *V, bool &Changed,
|
||||
Instruction *InsertPt = 0) const;
|
||||
Instruction *InsertPt = nullptr) const;
|
||||
|
||||
/// makeLoopInvariant - If the given instruction is inside of the
|
||||
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
|
||||
@ -369,7 +384,7 @@ public:
|
||||
/// If null, the terminator of the loop preheader is used.
|
||||
///
|
||||
bool makeLoopInvariant(Instruction *I, bool &Changed,
|
||||
Instruction *InsertPt = 0) const;
|
||||
Instruction *InsertPt = nullptr) const;
|
||||
|
||||
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
|
||||
/// induction variable: an integer recurrence that starts at 0 and increments
|
||||
@ -438,6 +453,31 @@ public:
|
||||
|
||||
void dump() const;
|
||||
|
||||
/// \brief Return the debug location of the start of this loop.
|
||||
/// This looks for a BB terminating instruction with a known debug
|
||||
/// location by looking at the preheader and header blocks. If it
|
||||
/// cannot find a terminating instruction with location information,
|
||||
/// it returns an unknown location.
|
||||
DebugLoc getStartLoc() const {
|
||||
DebugLoc StartLoc;
|
||||
BasicBlock *HeadBB;
|
||||
|
||||
// Try the pre-header first.
|
||||
if ((HeadBB = getLoopPreheader()) != nullptr) {
|
||||
StartLoc = HeadBB->getTerminator()->getDebugLoc();
|
||||
if (!StartLoc.isUnknown())
|
||||
return StartLoc;
|
||||
}
|
||||
|
||||
// If we have no pre-header or there are no instructions with debug
|
||||
// info in it, try the header.
|
||||
HeadBB = getHeader();
|
||||
if (HeadBB)
|
||||
StartLoc = HeadBB->getTerminator()->getDebugLoc();
|
||||
|
||||
return StartLoc;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class LoopInfoBase<BasicBlock, Loop>;
|
||||
explicit Loop(BasicBlock *BB) : LoopBase<BasicBlock, Loop>(BB) {}
|
||||
@ -516,7 +556,7 @@ public:
|
||||
LoopT *removeLoop(iterator I) {
|
||||
assert(I != end() && "Cannot remove end iterator!");
|
||||
LoopT *L = *I;
|
||||
assert(L->getParentLoop() == 0 && "Not a top-level loop!");
|
||||
assert(!L->getParentLoop() && "Not a top-level loop!");
|
||||
TopLevelLoops.erase(TopLevelLoops.begin() + (I-begin()));
|
||||
return L;
|
||||
}
|
||||
@ -540,14 +580,14 @@ public:
|
||||
std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
|
||||
assert(I != TopLevelLoops.end() && "Old loop not at top level!");
|
||||
*I = NewLoop;
|
||||
assert(NewLoop->ParentLoop == 0 && OldLoop->ParentLoop == 0 &&
|
||||
assert(!NewLoop->ParentLoop && !OldLoop->ParentLoop &&
|
||||
"Loops already embedded into a subloop!");
|
||||
}
|
||||
|
||||
/// addTopLevelLoop - This adds the specified loop to the collection of
|
||||
/// top-level loops.
|
||||
void addTopLevelLoop(LoopT *New) {
|
||||
assert(New->getParentLoop() == 0 && "Loop already in subloop!");
|
||||
assert(!New->getParentLoop() && "Loop already in subloop!");
|
||||
TopLevelLoops.push_back(New);
|
||||
}
|
||||
|
||||
@ -568,7 +608,7 @@ public:
|
||||
|
||||
static bool isNotAlreadyContainedIn(const LoopT *SubLoop,
|
||||
const LoopT *ParentLoop) {
|
||||
if (SubLoop == 0) return true;
|
||||
if (!SubLoop) return true;
|
||||
if (SubLoop == ParentLoop) return false;
|
||||
return isNotAlreadyContainedIn(SubLoop->getParentLoop(), ParentLoop);
|
||||
}
|
||||
@ -639,15 +679,15 @@ public:
|
||||
|
||||
/// runOnFunction - Calculate the natural loop information.
|
||||
///
|
||||
virtual bool runOnFunction(Function &F);
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
virtual void verifyAnalysis() const;
|
||||
void verifyAnalysis() const override;
|
||||
|
||||
virtual void releaseMemory() { LI.releaseMemory(); }
|
||||
void releaseMemory() override { LI.releaseMemory(); }
|
||||
|
||||
virtual void print(raw_ostream &O, const Module* M = 0) const;
|
||||
void print(raw_ostream &O, const Module* M = nullptr) const override;
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// removeLoop - This removes the specified top-level loop from this loop info
|
||||
/// object. The loop is not deleted, as it will presumably be inserted into
|
||||
|
@ -15,9 +15,11 @@
|
||||
#ifndef LLVM_ANALYSIS_LOOPINFOIMPL_H
|
||||
#define LLVM_ANALYSIS_LOOPINFOIMPL_H
|
||||
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -51,7 +53,7 @@ BlockT *LoopBase<BlockT, LoopT>::getExitingBlock() const {
|
||||
getExitingBlocks(ExitingBlocks);
|
||||
if (ExitingBlocks.size() == 1)
|
||||
return ExitingBlocks[0];
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getExitBlocks - Return all of the successor blocks of this loop. These
|
||||
@ -78,7 +80,7 @@ BlockT *LoopBase<BlockT, LoopT>::getExitBlock() const {
|
||||
getExitBlocks(ExitBlocks);
|
||||
if (ExitBlocks.size() == 1)
|
||||
return ExitBlocks[0];
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
|
||||
@ -106,14 +108,14 @@ template<class BlockT, class LoopT>
|
||||
BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
|
||||
// Keep track of nodes outside the loop branching to the header...
|
||||
BlockT *Out = getLoopPredecessor();
|
||||
if (!Out) return 0;
|
||||
if (!Out) return nullptr;
|
||||
|
||||
// Make sure there is only one exit out of the preheader.
|
||||
typedef GraphTraits<BlockT*> BlockTraits;
|
||||
typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out);
|
||||
++SI;
|
||||
if (SI != BlockTraits::child_end(Out))
|
||||
return 0; // Multiple exits from the block, must not be a preheader.
|
||||
return nullptr; // Multiple exits from the block, must not be a preheader.
|
||||
|
||||
// The predecessor has exactly one successor, so it is a preheader.
|
||||
return Out;
|
||||
@ -127,7 +129,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
|
||||
template<class BlockT, class LoopT>
|
||||
BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
||||
// Keep track of nodes outside the loop branching to the header...
|
||||
BlockT *Out = 0;
|
||||
BlockT *Out = nullptr;
|
||||
|
||||
// Loop over the predecessors of the header node...
|
||||
BlockT *Header = getHeader();
|
||||
@ -138,7 +140,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
||||
typename InvBlockTraits::NodeType *N = *PI;
|
||||
if (!contains(N)) { // If the block is not in the loop...
|
||||
if (Out && Out != N)
|
||||
return 0; // Multiple predecessors outside the loop
|
||||
return nullptr; // Multiple predecessors outside the loop
|
||||
Out = N;
|
||||
}
|
||||
}
|
||||
@ -158,11 +160,11 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopLatch() const {
|
||||
InvBlockTraits::child_begin(Header);
|
||||
typename InvBlockTraits::ChildIteratorType PE =
|
||||
InvBlockTraits::child_end(Header);
|
||||
BlockT *Latch = 0;
|
||||
BlockT *Latch = nullptr;
|
||||
for (; PI != PE; ++PI) {
|
||||
typename InvBlockTraits::NodeType *N = *PI;
|
||||
if (contains(N)) {
|
||||
if (Latch) return 0;
|
||||
if (Latch) return nullptr;
|
||||
Latch = N;
|
||||
}
|
||||
}
|
||||
@ -186,7 +188,7 @@ addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LIB) {
|
||||
assert((Blocks.empty() || LIB[getHeader()] == this) &&
|
||||
"Incorrect LI specified for this loop!");
|
||||
assert(NewBB && "Cannot add a null basic block to the loop!");
|
||||
assert(LIB[NewBB] == 0 && "BasicBlock already in the loop!");
|
||||
assert(!LIB[NewBB] && "BasicBlock already in the loop!");
|
||||
|
||||
LoopT *L = static_cast<LoopT *>(this);
|
||||
|
||||
@ -208,12 +210,12 @@ template<class BlockT, class LoopT>
|
||||
void LoopBase<BlockT, LoopT>::
|
||||
replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild) {
|
||||
assert(OldChild->ParentLoop == this && "This loop is already broken!");
|
||||
assert(NewChild->ParentLoop == 0 && "NewChild already has a parent!");
|
||||
assert(!NewChild->ParentLoop && "NewChild already has a parent!");
|
||||
typename std::vector<LoopT *>::iterator I =
|
||||
std::find(SubLoops.begin(), SubLoops.end(), OldChild);
|
||||
assert(I != SubLoops.end() && "OldChild not in loop!");
|
||||
*I = NewChild;
|
||||
OldChild->ParentLoop = 0;
|
||||
OldChild->ParentLoop = nullptr;
|
||||
NewChild->ParentLoop = static_cast<LoopT *>(this);
|
||||
}
|
||||
|
||||
@ -268,11 +270,10 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
|
||||
// though it is permitted if the predecessor is not itself actually
|
||||
// reachable.
|
||||
BlockT *EntryBB = BB->getParent()->begin();
|
||||
for (df_iterator<BlockT *> NI = df_begin(EntryBB),
|
||||
NE = df_end(EntryBB); NI != NE; ++NI)
|
||||
for (unsigned i = 0, e = OutsideLoopPreds.size(); i != e; ++i)
|
||||
assert(*NI != OutsideLoopPreds[i] &&
|
||||
"Loop has multiple entry points!");
|
||||
for (BlockT *CB : depth_first(EntryBB))
|
||||
for (unsigned i = 0, e = OutsideLoopPreds.size(); i != e; ++i)
|
||||
assert(CB != OutsideLoopPreds[i] &&
|
||||
"Loop has multiple entry points!");
|
||||
}
|
||||
assert(HasInsideLoopPreds && "Loop block has no in-loop predecessors!");
|
||||
assert(HasInsideLoopSuccs && "Loop block has no in-loop successors!");
|
||||
@ -322,7 +323,7 @@ void LoopBase<BlockT, LoopT>::print(raw_ostream &OS, unsigned Depth) const {
|
||||
for (unsigned i = 0; i < getBlocks().size(); ++i) {
|
||||
if (i) OS << ",";
|
||||
BlockT *BB = getBlocks()[i];
|
||||
WriteAsOperand(OS, BB, false);
|
||||
BB->printAsOperand(OS, false);
|
||||
if (BB == getHeader()) OS << "<header>";
|
||||
if (BB == getLoopLatch()) OS << "<latch>";
|
||||
if (isLoopExiting(BB)) OS << "<exiting>";
|
||||
|
@ -32,7 +32,8 @@ public:
|
||||
|
||||
/// getPrinterPass - Get a pass to print the function corresponding
|
||||
/// to a Loop.
|
||||
Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const;
|
||||
Pass *createPrinterPass(raw_ostream &O,
|
||||
const std::string &Banner) const override;
|
||||
|
||||
// runOnLoop - This method should be implemented by the subclass to perform
|
||||
// whatever action is necessary for the specified Loop.
|
||||
@ -56,14 +57,13 @@ public:
|
||||
// LPPassManager passes. In such case, pop LPPassManager from the
|
||||
// stack. This will force assignPassManager() to create new
|
||||
// LPPassManger as expected.
|
||||
void preparePassManager(PMStack &PMS);
|
||||
void preparePassManager(PMStack &PMS) override;
|
||||
|
||||
/// Assign pass manager to manage this pass
|
||||
virtual void assignPassManager(PMStack &PMS,
|
||||
PassManagerType PMT);
|
||||
void assignPassManager(PMStack &PMS, PassManagerType PMT) override;
|
||||
|
||||
/// Return what kind of Pass Manager can manage this pass.
|
||||
virtual PassManagerType getPotentialPassManagerType() const {
|
||||
PassManagerType getPotentialPassManagerType() const override {
|
||||
return PMT_LoopPassManager;
|
||||
}
|
||||
|
||||
@ -81,6 +81,11 @@ public:
|
||||
|
||||
/// deleteAnalysisValue - Delete analysis info associated with value V.
|
||||
virtual void deleteAnalysisValue(Value *V, Loop *L) {}
|
||||
|
||||
protected:
|
||||
/// skipOptnoneFunction - Containing function has Attribute::OptimizeNone
|
||||
/// and most transformation passes should skip it.
|
||||
bool skipOptnoneFunction(const Loop *L) const;
|
||||
};
|
||||
|
||||
class LPPassManager : public FunctionPass, public PMDataManager {
|
||||
@ -90,21 +95,21 @@ public:
|
||||
|
||||
/// run - Execute all of the passes scheduled for execution. Keep track of
|
||||
/// whether any of the passes modifies the module, and if so, return true.
|
||||
bool runOnFunction(Function &F);
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
/// Pass Manager itself does not invalidate any analysis info.
|
||||
// LPPassManager needs LoopInfo.
|
||||
void getAnalysisUsage(AnalysisUsage &Info) const;
|
||||
void getAnalysisUsage(AnalysisUsage &Info) const override;
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
const char *getPassName() const override {
|
||||
return "Loop Pass Manager";
|
||||
}
|
||||
|
||||
virtual PMDataManager *getAsPMDataManager() { return this; }
|
||||
virtual Pass *getAsPass() { return this; }
|
||||
PMDataManager *getAsPMDataManager() override { return this; }
|
||||
Pass *getAsPass() override { return this; }
|
||||
|
||||
/// Print passes managed by this manager
|
||||
void dumpPassStructure(unsigned Offset);
|
||||
void dumpPassStructure(unsigned Offset) override;
|
||||
|
||||
LoopPass *getContainedPass(unsigned N) {
|
||||
assert(N < PassVector.size() && "Pass number out of range!");
|
||||
@ -112,7 +117,7 @@ public:
|
||||
return LP;
|
||||
}
|
||||
|
||||
virtual PassManagerType getPassManagerType() const {
|
||||
PassManagerType getPassManagerType() const override {
|
||||
return PMT_LoopPassManager;
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,12 @@
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/TargetFolder.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/InstVisitor.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/TargetFolder.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
|
||||
namespace llvm {
|
||||
class CallInst;
|
||||
@ -190,6 +190,8 @@ public:
|
||||
return knownSize(SizeOffset) && knownOffset(SizeOffset);
|
||||
}
|
||||
|
||||
// These are "private", except they can't actually be made private. Only
|
||||
// compute() should be used by external users.
|
||||
SizeOffsetType visitAllocaInst(AllocaInst &I);
|
||||
SizeOffsetType visitArgument(Argument &A);
|
||||
SizeOffsetType visitCallSite(CallSite CS);
|
||||
@ -231,7 +233,7 @@ class ObjectSizeOffsetEvaluator
|
||||
bool RoundToAlign;
|
||||
|
||||
SizeOffsetEvalType unknown() {
|
||||
return std::make_pair((Value*)0, (Value*)0);
|
||||
return std::make_pair(nullptr, nullptr);
|
||||
}
|
||||
SizeOffsetEvalType compute_(Value *V);
|
||||
|
||||
@ -256,6 +258,7 @@ public:
|
||||
return knownSize(SizeOffset) && knownOffset(SizeOffset);
|
||||
}
|
||||
|
||||
// The individual instruction visitors should be treated as private.
|
||||
SizeOffsetEvalType visitAllocaInst(AllocaInst &I);
|
||||
SizeOffsetEvalType visitCallSite(CallSite CS);
|
||||
SizeOffsetEvalType visitExtractElementInst(ExtractElementInst &I);
|
||||
|
@ -15,13 +15,12 @@
|
||||
#define LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
@ -98,7 +97,7 @@ namespace llvm {
|
||||
PairTy Value;
|
||||
explicit MemDepResult(PairTy V) : Value(V) {}
|
||||
public:
|
||||
MemDepResult() : Value(0, Invalid) {}
|
||||
MemDepResult() : Value(nullptr, Invalid) {}
|
||||
|
||||
/// get methods: These are static ctor methods for creating various
|
||||
/// MemDepResult kinds.
|
||||
@ -156,7 +155,7 @@ namespace llvm {
|
||||
/// getInst() - If this is a normal dependency, return the instruction that
|
||||
/// is depended on. Otherwise, return null.
|
||||
Instruction *getInst() const {
|
||||
if (Value.getInt() == Other) return NULL;
|
||||
if (Value.getInt() == Other) return nullptr;
|
||||
return Value.getPointer();
|
||||
}
|
||||
|
||||
@ -286,7 +285,8 @@ namespace llvm {
|
||||
/// pointer. May be null if there are no tags or conflicting tags.
|
||||
const MDNode *TBAATag;
|
||||
|
||||
NonLocalPointerInfo() : Size(AliasAnalysis::UnknownSize), TBAATag(0) {}
|
||||
NonLocalPointerInfo()
|
||||
: Size(AliasAnalysis::UnknownSize), TBAATag(nullptr) {}
|
||||
};
|
||||
|
||||
/// CachedNonLocalPointerInfo - This map stores the cached results of doing
|
||||
@ -323,24 +323,25 @@ namespace llvm {
|
||||
|
||||
/// Current AA implementation, just a cache.
|
||||
AliasAnalysis *AA;
|
||||
DataLayout *TD;
|
||||
const DataLayout *DL;
|
||||
DominatorTree *DT;
|
||||
OwningPtr<PredIteratorCache> PredCache;
|
||||
std::unique_ptr<PredIteratorCache> PredCache;
|
||||
|
||||
public:
|
||||
MemoryDependenceAnalysis();
|
||||
~MemoryDependenceAnalysis();
|
||||
static char ID;
|
||||
|
||||
/// Pass Implementation stuff. This doesn't do any analysis eagerly.
|
||||
bool runOnFunction(Function &);
|
||||
bool runOnFunction(Function &) override;
|
||||
|
||||
/// Clean up memory in between runs
|
||||
void releaseMemory();
|
||||
void releaseMemory() override;
|
||||
|
||||
/// getAnalysisUsage - Does not modify anything. It uses Value Numbering
|
||||
/// and Alias Analysis.
|
||||
///
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// getDependency - Return the instruction on which a memory operation
|
||||
/// depends. See the class comment for more details. It is illegal to call
|
||||
@ -401,7 +402,7 @@ namespace llvm {
|
||||
bool isLoad,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB,
|
||||
Instruction *QueryInst = 0);
|
||||
Instruction *QueryInst = nullptr);
|
||||
|
||||
|
||||
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
|
||||
@ -415,7 +416,7 @@ namespace llvm {
|
||||
int64_t MemLocOffs,
|
||||
unsigned MemLocSize,
|
||||
const LoadInst *LI,
|
||||
const DataLayout &TD);
|
||||
const DataLayout &DL);
|
||||
|
||||
private:
|
||||
MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall,
|
||||
|
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