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;
|
# xargs -n1 | sort | uniq -d;
|
||||||
# done
|
# 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
|
# 20141226: Remove gpib/ieee488
|
||||||
OLD_FILES+=usr/include/dev/ieee488/ibfoo_int.h
|
OLD_FILES+=usr/include/dev/ieee488/ibfoo_int.h
|
||||||
OLD_FILES+=usr/include/dev/ieee488/tnt4882.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
|
disable the most expensive debugging functionality run
|
||||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
"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:
|
20141222:
|
||||||
The old NFS client and server (kernel options NFSCLIENT, NFSSERVER)
|
The old NFS client and server (kernel options NFSCLIENT, NFSSERVER)
|
||||||
kernel sources have been removed. The .h files remain, since some
|
kernel sources have been removed. The .h files remain, since some
|
||||||
|
@ -4,7 +4,7 @@ LLVM Release License
|
|||||||
University of Illinois/NCSA
|
University of Illinois/NCSA
|
||||||
Open Source License
|
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.
|
All rights reserved.
|
||||||
|
|
||||||
Developed by:
|
Developed by:
|
||||||
@ -63,7 +63,6 @@ Program Directory
|
|||||||
------- ---------
|
------- ---------
|
||||||
Autoconf llvm/autoconf
|
Autoconf llvm/autoconf
|
||||||
llvm/projects/ModuleMaker/autoconf
|
llvm/projects/ModuleMaker/autoconf
|
||||||
llvm/projects/sample/autoconf
|
|
||||||
Google Test llvm/utils/unittest/googletest
|
Google Test llvm/utils/unittest/googletest
|
||||||
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
|
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
|
||||||
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
|
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#ifndef LLVM_C_CORE_H
|
#ifndef LLVM_C_CORE_H
|
||||||
#define LLVM_C_CORE_H
|
#define LLVM_C_CORE_H
|
||||||
|
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm-c/Support.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -62,8 +62,6 @@ extern "C" {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef int LLVMBool;
|
|
||||||
|
|
||||||
/* Opaque types. */
|
/* Opaque types. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,13 +112,6 @@ typedef struct LLVMOpaqueBuilder *LLVMBuilderRef;
|
|||||||
*/
|
*/
|
||||||
typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef;
|
typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef;
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to provide a module to JIT or interpreter.
|
|
||||||
*
|
|
||||||
* @see llvm::MemoryBuffer
|
|
||||||
*/
|
|
||||||
typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef;
|
|
||||||
|
|
||||||
/** @see llvm::PassManagerBase */
|
/** @see llvm::PassManagerBase */
|
||||||
typedef struct LLVMOpaquePassManager *LLVMPassManagerRef;
|
typedef struct LLVMOpaquePassManager *LLVMPassManagerRef;
|
||||||
|
|
||||||
@ -133,6 +124,12 @@ typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef;
|
|||||||
* @see llvm::Use */
|
* @see llvm::Use */
|
||||||
typedef struct LLVMOpaqueUse *LLVMUseRef;
|
typedef struct LLVMOpaqueUse *LLVMUseRef;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see llvm::DiagnosticInfo
|
||||||
|
*/
|
||||||
|
typedef struct LLVMOpaqueDiagnosticInfo *LLVMDiagnosticInfoRef;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LLVMZExtAttribute = 1<<0,
|
LLVMZExtAttribute = 1<<0,
|
||||||
LLVMSExtAttribute = 1<<1,
|
LLVMSExtAttribute = 1<<1,
|
||||||
@ -167,7 +164,11 @@ typedef enum {
|
|||||||
LLVMAddressSafety = 1ULL << 32,
|
LLVMAddressSafety = 1ULL << 32,
|
||||||
LLVMStackProtectStrongAttribute = 1ULL<<33,
|
LLVMStackProtectStrongAttribute = 1ULL<<33,
|
||||||
LLVMCold = 1ULL << 34,
|
LLVMCold = 1ULL << 34,
|
||||||
LLVMOptimizeNone = 1ULL << 35
|
LLVMOptimizeNone = 1ULL << 35,
|
||||||
|
LLVMInAllocaAttribute = 1ULL << 36,
|
||||||
|
LLVMNonNullAttribute = 1ULL << 37,
|
||||||
|
LLVMJumpTableAttribute = 1ULL << 38,
|
||||||
|
LLVMDereferenceableAttribute = 1ULL << 39,
|
||||||
*/
|
*/
|
||||||
} LLVMAttribute;
|
} LLVMAttribute;
|
||||||
|
|
||||||
@ -283,8 +284,8 @@ typedef enum {
|
|||||||
LLVMInternalLinkage, /**< Rename collisions when linking (static
|
LLVMInternalLinkage, /**< Rename collisions when linking (static
|
||||||
functions) */
|
functions) */
|
||||||
LLVMPrivateLinkage, /**< Like Internal, but omit from symbol table */
|
LLVMPrivateLinkage, /**< Like Internal, but omit from symbol table */
|
||||||
LLVMDLLImportLinkage, /**< Function to be imported from DLL */
|
LLVMDLLImportLinkage, /**< Obsolete */
|
||||||
LLVMDLLExportLinkage, /**< Function to be accessible from DLL */
|
LLVMDLLExportLinkage, /**< Obsolete */
|
||||||
LLVMExternalWeakLinkage,/**< ExternalWeak linkage description */
|
LLVMExternalWeakLinkage,/**< ExternalWeak linkage description */
|
||||||
LLVMGhostLinkage, /**< Obsolete */
|
LLVMGhostLinkage, /**< Obsolete */
|
||||||
LLVMCommonLinkage, /**< Tentative definitions */
|
LLVMCommonLinkage, /**< Tentative definitions */
|
||||||
@ -298,6 +299,12 @@ typedef enum {
|
|||||||
LLVMProtectedVisibility /**< The GV is protected */
|
LLVMProtectedVisibility /**< The GV is protected */
|
||||||
} LLVMVisibility;
|
} LLVMVisibility;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LLVMDefaultStorageClass = 0,
|
||||||
|
LLVMDLLImportStorageClass = 1, /**< Function to be imported from DLL. */
|
||||||
|
LLVMDLLExportStorageClass = 2 /**< Function to be accessible from DLL. */
|
||||||
|
} LLVMDLLStorageClass;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LLVMCCallConv = 0,
|
LLVMCCallConv = 0,
|
||||||
LLVMFastCallConv = 8,
|
LLVMFastCallConv = 8,
|
||||||
@ -402,6 +409,13 @@ typedef enum {
|
|||||||
the old one */
|
the old one */
|
||||||
} LLVMAtomicRMWBinOp;
|
} 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.
|
* Create a new context.
|
||||||
*
|
*
|
||||||
@ -468,6 +485,21 @@ LLVMContextRef LLVMContextCreate(void);
|
|||||||
*/
|
*/
|
||||||
LLVMContextRef LLVMGetGlobalContext(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.
|
* Destroy a context instance.
|
||||||
*
|
*
|
||||||
@ -476,6 +508,21 @@ LLVMContextRef LLVMGetGlobalContext(void);
|
|||||||
*/
|
*/
|
||||||
void LLVMContextDispose(LLVMContextRef C);
|
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 LLVMGetMDKindIDInContext(LLVMContextRef C, const char* Name,
|
||||||
unsigned SLen);
|
unsigned SLen);
|
||||||
unsigned LLVMGetMDKindID(const char* Name, unsigned SLen);
|
unsigned LLVMGetMDKindID(const char* Name, unsigned SLen);
|
||||||
@ -1123,9 +1170,10 @@ LLVMTypeRef LLVMX86MMXType(void);
|
|||||||
macro(ConstantStruct) \
|
macro(ConstantStruct) \
|
||||||
macro(ConstantVector) \
|
macro(ConstantVector) \
|
||||||
macro(GlobalValue) \
|
macro(GlobalValue) \
|
||||||
macro(Function) \
|
|
||||||
macro(GlobalAlias) \
|
macro(GlobalAlias) \
|
||||||
macro(GlobalVariable) \
|
macro(GlobalObject) \
|
||||||
|
macro(Function) \
|
||||||
|
macro(GlobalVariable) \
|
||||||
macro(UndefValue) \
|
macro(UndefValue) \
|
||||||
macro(Instruction) \
|
macro(Instruction) \
|
||||||
macro(BinaryOperator) \
|
macro(BinaryOperator) \
|
||||||
@ -1688,6 +1736,10 @@ const char *LLVMGetSection(LLVMValueRef Global);
|
|||||||
void LLVMSetSection(LLVMValueRef Global, const char *Section);
|
void LLVMSetSection(LLVMValueRef Global, const char *Section);
|
||||||
LLVMVisibility LLVMGetVisibility(LLVMValueRef Global);
|
LLVMVisibility LLVMGetVisibility(LLVMValueRef Global);
|
||||||
void LLVMSetVisibility(LLVMValueRef Global, LLVMVisibility Viz);
|
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
|
* @defgroup LLVMCCoreValueWithAlignment Values with alignment
|
||||||
@ -1698,6 +1750,7 @@ void LLVMSetVisibility(LLVMValueRef Global, LLVMVisibility Viz);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the preferred alignment of the value.
|
* Obtain the preferred alignment of the value.
|
||||||
|
* @see llvm::AllocaInst::getAlignment()
|
||||||
* @see llvm::LoadInst::getAlignment()
|
* @see llvm::LoadInst::getAlignment()
|
||||||
* @see llvm::StoreInst::getAlignment()
|
* @see llvm::StoreInst::getAlignment()
|
||||||
* @see llvm::GlobalValue::getAlignment()
|
* @see llvm::GlobalValue::getAlignment()
|
||||||
@ -1706,6 +1759,7 @@ unsigned LLVMGetAlignment(LLVMValueRef V);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the preferred alignment of the value.
|
* Set the preferred alignment of the value.
|
||||||
|
* @see llvm::AllocaInst::setAlignment()
|
||||||
* @see llvm::LoadInst::setAlignment()
|
* @see llvm::LoadInst::setAlignment()
|
||||||
* @see llvm::StoreInst::setAlignment()
|
* @see llvm::StoreInst::setAlignment()
|
||||||
* @see llvm::GlobalValue::setAlignment()
|
* @see llvm::GlobalValue::setAlignment()
|
||||||
@ -2663,7 +2717,9 @@ LLVMValueRef LLVMBuildIsNotNull(LLVMBuilderRef, LLVMValueRef Val,
|
|||||||
const char *Name);
|
const char *Name);
|
||||||
LLVMValueRef LLVMBuildPtrDiff(LLVMBuilderRef, LLVMValueRef LHS,
|
LLVMValueRef LLVMBuildPtrDiff(LLVMBuilderRef, LLVMValueRef LHS,
|
||||||
LLVMValueRef RHS, const char *Name);
|
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,
|
LLVMValueRef PTR, LLVMValueRef Val,
|
||||||
LLVMAtomicOrdering ordering,
|
LLVMAtomicOrdering ordering,
|
||||||
LLVMBool singleThread);
|
LLVMBool singleThread);
|
||||||
@ -2793,16 +2849,13 @@ void LLVMDisposePassManager(LLVMPassManagerRef PM);
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Allocate and initialize structures needed to make LLVM safe for
|
/** Deprecated: Multi-threading can only be enabled/disabled with the compile
|
||||||
multithreading. The return value indicates whether multithreaded
|
time define LLVM_ENABLE_THREADS. This function always returns
|
||||||
initialization succeeded. Must be executed in isolation from all
|
LLVMIsMultithreaded(). */
|
||||||
other LLVM api calls.
|
|
||||||
@see llvm::llvm_start_multithreaded */
|
|
||||||
LLVMBool LLVMStartMultithreaded(void);
|
LLVMBool LLVMStartMultithreaded(void);
|
||||||
|
|
||||||
/** Deallocate structures necessary to make LLVM safe for multithreading.
|
/** Deprecated: Multi-threading can only be enabled/disabled with the compile
|
||||||
Must be executed in isolation from all other LLVM api calls.
|
time define LLVM_ENABLE_THREADS. */
|
||||||
@see llvm::llvm_stop_multithreaded */
|
|
||||||
void LLVMStopMultithreaded(void);
|
void LLVMStopMultithreaded(void);
|
||||||
|
|
||||||
/** Check whether LLVM is executing in thread-safe mode or not.
|
/** 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_HI16 1 /* :upper16: */
|
||||||
#define LLVMDisassembler_VariantKind_ARM_LO16 2 /* :lower16: */
|
#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
|
* 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
|
* 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. */
|
/* The input reference is from a PC relative load instruction. */
|
||||||
#define LLVMDisassembler_ReferenceType_In_PCrel_Load 2
|
#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. */
|
/* The output reference is to as symbol stub. */
|
||||||
#define LLVMDisassembler_ReferenceType_Out_SymbolStub 1
|
#define LLVMDisassembler_ReferenceType_Out_SymbolStub 1
|
||||||
/* The output reference is to a symbol address in a literal pool. */
|
/* 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. */
|
/* The output reference is to a Objective-C class ref. */
|
||||||
#define LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref 8
|
#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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* !defined(__cplusplus) */
|
#endif /* !defined(__cplusplus) */
|
||||||
|
@ -163,6 +163,8 @@ void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE,
|
|||||||
LLVMValueRef Fn);
|
LLVMValueRef Fn);
|
||||||
|
|
||||||
LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE);
|
LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE);
|
||||||
|
LLVMTargetMachineRef
|
||||||
|
LLVMGetExecutionEngineTargetMachine(LLVMExecutionEngineRef EE);
|
||||||
|
|
||||||
void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
|
void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
|
||||||
void* Addr);
|
void* Addr);
|
||||||
|
@ -24,7 +24,7 @@ extern "C" {
|
|||||||
* Read LLVM IR from a memory buffer and convert it into an in-memory Module
|
* Read LLVM IR from a memory buffer and convert it into an in-memory Module
|
||||||
* object. Returns 0 on success.
|
* object. Returns 0 on success.
|
||||||
* Optionally returns a human-readable description of any errors that
|
* 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.
|
* LLVMDisposeMessage.
|
||||||
*
|
*
|
||||||
* @see llvm::ParseIR()
|
* @see llvm::ParseIR()
|
||||||
|
@ -78,7 +78,6 @@ void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef RI);
|
|||||||
// SymbolRef accessors
|
// SymbolRef accessors
|
||||||
const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI);
|
const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI);
|
||||||
uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI);
|
uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI);
|
||||||
uint64_t LLVMGetSymbolFileOffset(LLVMSymbolIteratorRef SI);
|
|
||||||
uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI);
|
uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI);
|
||||||
|
|
||||||
// RelocationRef accessors
|
// RelocationRef accessors
|
||||||
|
@ -14,12 +14,31 @@
|
|||||||
#ifndef LLVM_C_SUPPORT_H
|
#ifndef LLVM_C_SUPPORT_H
|
||||||
#define LLVM_C_SUPPORT_H
|
#define LLVM_C_SUPPORT_H
|
||||||
|
|
||||||
#include "llvm-c/Core.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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.
|
* This function permanently loads the dynamic library at the given path.
|
||||||
* It is safe to call this function multiple times for the same library.
|
* It is safe to call this function multiple times for the same library.
|
||||||
|
@ -62,7 +62,7 @@ LLVMTargetRef LLVMGetFirstTarget(void);
|
|||||||
LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T);
|
LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T);
|
||||||
|
|
||||||
/*===-- Target ------------------------------------------------------------===*/
|
/*===-- 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. */
|
Returns 0 on success. */
|
||||||
LLVMTargetRef LLVMGetTargetFromName(const char *Name);
|
LLVMTargetRef LLVMGetTargetFromName(const char *Name);
|
||||||
|
|
||||||
@ -137,6 +137,9 @@ LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T, LLVMModuleR
|
|||||||
disposed with LLVMDisposeMessage. */
|
disposed with LLVMDisposeMessage. */
|
||||||
char* LLVMGetDefaultTargetTriple(void);
|
char* LLVMGetDefaultTargetTriple(void);
|
||||||
|
|
||||||
|
/** Adds the target-specific analysis passes to the pass manager. */
|
||||||
|
void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
typedef struct LLVMOpaquePassManagerBuilder *LLVMPassManagerBuilderRef;
|
typedef struct LLVMOpaquePassManagerBuilder *LLVMPassManagerBuilderRef;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ void LLVMAddCFGSimplificationPass(LLVMPassManagerRef PM);
|
|||||||
/** See llvm::createDeadStoreEliminationPass function. */
|
/** See llvm::createDeadStoreEliminationPass function. */
|
||||||
void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM);
|
void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM);
|
||||||
|
|
||||||
|
/** See llvm::createScalarizerPass function. */
|
||||||
|
void LLVMAddScalarizerPass(LLVMPassManagerRef PM);
|
||||||
|
|
||||||
|
/** See llvm::createMergedLoadStoreMotionPass function. */
|
||||||
|
void LLVMAddMergedLoadStoreMotionPass(LLVMPassManagerRef PM);
|
||||||
|
|
||||||
/** See llvm::createGVNPass function. */
|
/** See llvm::createGVNPass function. */
|
||||||
void LLVMAddGVNPass(LLVMPassManagerRef PM);
|
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 {
|
typedef enum {
|
||||||
LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */
|
LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */
|
||||||
LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0,
|
LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0,
|
||||||
@ -62,23 +65,29 @@ typedef enum {
|
|||||||
LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN = 0x00002800
|
LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN = 0x00002800
|
||||||
} lto_symbol_attributes;
|
} lto_symbol_attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LTO_DEBUG_MODEL_NONE = 0,
|
LTO_DEBUG_MODEL_NONE = 0,
|
||||||
LTO_DEBUG_MODEL_DWARF = 1
|
LTO_DEBUG_MODEL_DWARF = 1
|
||||||
} lto_debug_model;
|
} lto_debug_model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LTO_CODEGEN_PIC_MODEL_STATIC = 0,
|
LTO_CODEGEN_PIC_MODEL_STATIC = 0,
|
||||||
LTO_CODEGEN_PIC_MODEL_DYNAMIC = 1,
|
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;
|
} lto_codegen_model;
|
||||||
|
|
||||||
|
|
||||||
/** opaque reference to a loaded object module */
|
/** 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 */
|
/** opaque reference to a code generator */
|
||||||
typedef struct LTOCodeGenerator* lto_code_gen_t;
|
typedef struct LLVMOpaqueLTOCodeGenerator *lto_code_gen_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -86,6 +95,8 @@ extern "C" {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a printable string.
|
* Returns a printable string.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern const char*
|
extern const char*
|
||||||
lto_get_version(void);
|
lto_get_version(void);
|
||||||
@ -93,12 +104,16 @@ lto_get_version(void);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the last error string or NULL if last operation was successful.
|
* Returns the last error string or NULL if last operation was successful.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern const char*
|
extern const char*
|
||||||
lto_get_error_message(void);
|
lto_get_error_message(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a file is a loadable object file.
|
* Checks if a file is a loadable object file.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_module_is_object_file(const char* path);
|
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.
|
* Checks if a file is a loadable object compiled for requested target.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_module_is_object_file_for_target(const char* path,
|
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.
|
* Checks if a buffer is a loadable object file.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_module_is_object_file_in_memory(const void* mem, size_t length);
|
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.
|
* Checks if a buffer is a loadable object compiled for requested target.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length,
|
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.
|
* Loads an object file from disk.
|
||||||
* Returns NULL on error (check lto_get_error_message() for details).
|
* Returns NULL on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_module_t
|
extern lto_module_t
|
||||||
lto_module_create(const char* path);
|
lto_module_create(const char* path);
|
||||||
@ -138,13 +161,27 @@ lto_module_create(const char* path);
|
|||||||
/**
|
/**
|
||||||
* Loads an object file from memory.
|
* Loads an object file from memory.
|
||||||
* Returns NULL on error (check lto_get_error_message() for details).
|
* Returns NULL on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_module_t
|
extern lto_module_t
|
||||||
lto_module_create_from_memory(const void* mem, size_t length);
|
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.
|
* 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).
|
* Returns NULL on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=5
|
||||||
*/
|
*/
|
||||||
extern lto_module_t
|
extern lto_module_t
|
||||||
lto_module_create_from_fd(int fd, const char *path, size_t file_size);
|
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.
|
* 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).
|
* Returns NULL on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=5
|
||||||
*/
|
*/
|
||||||
extern lto_module_t
|
extern lto_module_t
|
||||||
lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size,
|
lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size,
|
||||||
size_t map_size, off_t offset);
|
size_t map_size, off_t offset);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees all memory internally allocated by the module.
|
* Frees all memory internally allocated by the module.
|
||||||
* Upon return the lto_module_t is no longer valid.
|
* Upon return the lto_module_t is no longer valid.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_module_dispose(lto_module_t mod);
|
lto_module_dispose(lto_module_t mod);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns triple string which the object module was compiled under.
|
* Returns triple string which the object module was compiled under.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern const char*
|
extern const char*
|
||||||
lto_module_get_target_triple(lto_module_t mod);
|
lto_module_get_target_triple(lto_module_t mod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets triple string with which the object will be codegened.
|
* Sets triple string with which the object will be codegened.
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=4
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_module_set_target_triple(lto_module_t mod, const char *triple);
|
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.
|
* Returns the number of symbols in the object module.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern unsigned int
|
extern unsigned int
|
||||||
lto_module_get_num_symbols(lto_module_t mod);
|
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.
|
* Returns the name of the ith symbol in the object module.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern const char*
|
extern const char*
|
||||||
lto_module_get_symbol_name(lto_module_t mod, unsigned int index);
|
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.
|
* Returns the attributes of the ith symbol in the object module.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_symbol_attributes
|
extern lto_symbol_attributes
|
||||||
lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index);
|
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.
|
* Instantiates a code generator.
|
||||||
* Returns NULL on error (check lto_get_error_message() for details).
|
* Returns NULL on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_code_gen_t
|
extern lto_code_gen_t
|
||||||
lto_codegen_create(void);
|
lto_codegen_create(void);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees all code generator and all memory it internally allocated.
|
* Frees all code generator and all memory it internally allocated.
|
||||||
* Upon return the lto_code_gen_t is no longer valid.
|
* Upon return the lto_code_gen_t is no longer valid.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_codegen_dispose(lto_code_gen_t);
|
lto_codegen_dispose(lto_code_gen_t);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an object module to the set of modules for which code will be generated.
|
* 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).
|
* Returns true on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod);
|
lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets if debug info should be generated.
|
* Sets if debug info should be generated.
|
||||||
* Returns true on error (check lto_get_error_message() for details).
|
* Returns true on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model);
|
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.
|
* Sets which PIC code model to generated.
|
||||||
* Returns true on error (check lto_get_error_message() for details).
|
* Returns true on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model);
|
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.
|
* Sets the cpu to generate code for.
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=4
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu);
|
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
|
* Sets the location of the assembler tool to run. If not set, libLTO
|
||||||
* will use gcc to invoke the assembler.
|
* will use gcc to invoke the assembler.
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path);
|
lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets extra arguments that libLTO should pass to the assembler.
|
* Sets extra arguments that libLTO should pass to the assembler.
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=4
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args,
|
lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args,
|
||||||
int nargs);
|
int nargs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells LTO optimization passes that this symbol must be preserved
|
* Adds to a list of all global symbols that must exist in the final generated
|
||||||
* because it is referenced by native code or a command line option.
|
* 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
|
extern void
|
||||||
lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol);
|
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
|
* Writes a new object file at the specified path that contains the
|
||||||
* merged contents of all modules added so far.
|
* merged contents of all modules added so far.
|
||||||
* Returns true on error (check lto_get_error_message() for details).
|
* Returns true on error (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=5
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path);
|
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()
|
* lto_code_gen_t and will be freed when lto_codegen_dispose()
|
||||||
* is called, or lto_codegen_compile() is called again.
|
* is called, or lto_codegen_compile() is called again.
|
||||||
* On failure, returns NULL (check lto_get_error_message() for details).
|
* On failure, returns NULL (check lto_get_error_message() for details).
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern const void*
|
extern const void*
|
||||||
lto_codegen_compile(lto_code_gen_t cg, size_t* length);
|
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.
|
* Generates code for all added modules into one native object file.
|
||||||
* The name of the file is written to name. Returns true on error.
|
* The name of the file is written to name. Returns true on error.
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=5
|
||||||
*/
|
*/
|
||||||
extern lto_bool_t
|
extern lto_bool_t
|
||||||
lto_codegen_compile_to_file(lto_code_gen_t cg, const char** name);
|
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.
|
* Sets options to help debug codegen bugs.
|
||||||
|
*
|
||||||
|
* \since prior to LTO_API_VERSION=3
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_codegen_debug_options(lto_code_gen_t cg, const char *);
|
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.
|
* Initializes LLVM disassemblers.
|
||||||
* FIXME: This doesn't really belong here.
|
* FIXME: This doesn't really belong here.
|
||||||
|
*
|
||||||
|
* \since LTO_API_VERSION=5
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
lto_initialize_disassembler(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
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -196,6 +196,7 @@ public:
|
|||||||
explicit APFloat(double d);
|
explicit APFloat(double d);
|
||||||
explicit APFloat(float f);
|
explicit APFloat(float f);
|
||||||
APFloat(const APFloat &);
|
APFloat(const APFloat &);
|
||||||
|
APFloat(APFloat &&);
|
||||||
~APFloat();
|
~APFloat();
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@ -235,19 +236,19 @@ public:
|
|||||||
APInt fill(64, type);
|
APInt fill(64, type);
|
||||||
return getQNaN(Sem, Negative, &fill);
|
return getQNaN(Sem, Negative, &fill);
|
||||||
} else {
|
} else {
|
||||||
return getQNaN(Sem, Negative, 0);
|
return getQNaN(Sem, Negative, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Factory for QNaN values.
|
/// Factory for QNaN values.
|
||||||
static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
|
static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
|
||||||
const APInt *payload = 0) {
|
const APInt *payload = nullptr) {
|
||||||
return makeNaN(Sem, false, Negative, payload);
|
return makeNaN(Sem, false, Negative, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Factory for SNaN values.
|
/// Factory for SNaN values.
|
||||||
static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
|
static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
|
||||||
const APInt *payload = 0) {
|
const APInt *payload = nullptr) {
|
||||||
return makeNaN(Sem, true, Negative, payload);
|
return makeNaN(Sem, true, Negative, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +412,7 @@ public:
|
|||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
APFloat &operator=(const APFloat &);
|
APFloat &operator=(const APFloat &);
|
||||||
|
APFloat &operator=(APFloat &&);
|
||||||
|
|
||||||
/// \brief Overload to compute a hash code for an APFloat value.
|
/// \brief Overload to compute a hash code for an APFloat value.
|
||||||
///
|
///
|
||||||
@ -498,7 +500,8 @@ private:
|
|||||||
|
|
||||||
void makeLargest(bool Neg = false);
|
void makeLargest(bool Neg = false);
|
||||||
void makeSmallest(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,
|
static APFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
|
||||||
const APInt *fill);
|
const APInt *fill);
|
||||||
void makeInf(bool Neg = false);
|
void makeInf(bool Neg = false);
|
||||||
|
@ -284,12 +284,10 @@ public:
|
|||||||
initSlowCase(that);
|
initSlowCase(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
/// \brief Move Constructor.
|
/// \brief Move Constructor.
|
||||||
APInt(APInt &&that) : BitWidth(that.BitWidth), VAL(that.VAL) {
|
APInt(APInt &&that) : BitWidth(that.BitWidth), VAL(that.VAL) {
|
||||||
that.BitWidth = 0;
|
that.BitWidth = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// \brief Destructor.
|
/// \brief Destructor.
|
||||||
~APInt() {
|
~APInt() {
|
||||||
@ -656,7 +654,6 @@ public:
|
|||||||
return AssignSlowCase(RHS);
|
return AssignSlowCase(RHS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
/// @brief Move assignment operator.
|
/// @brief Move assignment operator.
|
||||||
APInt &operator=(APInt &&that) {
|
APInt &operator=(APInt &&that) {
|
||||||
if (!isSingleWord())
|
if (!isSingleWord())
|
||||||
@ -669,7 +666,6 @@ public:
|
|||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// \brief Assignment operator.
|
/// \brief Assignment operator.
|
||||||
///
|
///
|
||||||
@ -1265,7 +1261,7 @@ public:
|
|||||||
/// \returns the number of words to hold the integer value with a given bit
|
/// \returns the number of words to hold the integer value with a given bit
|
||||||
/// width.
|
/// width.
|
||||||
static unsigned getNumWords(unsigned BitWidth) {
|
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
|
/// \brief Compute the number of active bits in the value
|
||||||
@ -1504,6 +1500,35 @@ public:
|
|||||||
return BitWidth - (*this - 1).countLeadingZeros();
|
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
|
/// \returns the log base 2 of this APInt if its an exact power of two, -1
|
||||||
/// otherwise
|
/// otherwise
|
||||||
int32_t exactLogBase2() const {
|
int32_t exactLogBase2() const {
|
||||||
|
@ -30,18 +30,12 @@ public:
|
|||||||
explicit APSInt(uint32_t BitWidth, bool isUnsigned = true)
|
explicit APSInt(uint32_t BitWidth, bool isUnsigned = true)
|
||||||
: APInt(BitWidth, 0), IsUnsigned(isUnsigned) {}
|
: APInt(BitWidth, 0), IsUnsigned(isUnsigned) {}
|
||||||
|
|
||||||
explicit APSInt(const APInt &I, bool isUnsigned = true)
|
explicit APSInt(APInt I, bool isUnsigned = true)
|
||||||
: APInt(I), IsUnsigned(isUnsigned) {}
|
: APInt(std::move(I)), IsUnsigned(isUnsigned) {}
|
||||||
|
|
||||||
APSInt &operator=(const APSInt &RHS) {
|
APSInt &operator=(APInt RHS) {
|
||||||
APInt::operator=(RHS);
|
|
||||||
IsUnsigned = RHS.IsUnsigned;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
APSInt &operator=(const APInt &RHS) {
|
|
||||||
// Retain our current sign.
|
// Retain our current sign.
|
||||||
APInt::operator=(RHS);
|
APInt::operator=(std::move(RHS));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +56,7 @@ public:
|
|||||||
APInt::toString(Str, Radix, isSigned());
|
APInt::toString(Str, Radix, isSigned());
|
||||||
}
|
}
|
||||||
/// toString - Converts an APInt to a std::string. This is an inefficient
|
/// 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 {
|
std::string toString(unsigned Radix) const {
|
||||||
return APInt::toString(Radix, isSigned());
|
return APInt::toString(Radix, isSigned());
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,10 @@ namespace llvm {
|
|||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Construct an empty ArrayRef.
|
/// Construct an empty ArrayRef.
|
||||||
/*implicit*/ ArrayRef() : Data(0), Length(0) {}
|
/*implicit*/ ArrayRef() : Data(nullptr), Length(0) {}
|
||||||
|
|
||||||
/// Construct an empty ArrayRef from None.
|
/// 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.
|
/// Construct an ArrayRef from a single element.
|
||||||
/*implicit*/ ArrayRef(const T &OneElt)
|
/*implicit*/ ArrayRef(const T &OneElt)
|
||||||
@ -76,7 +76,7 @@ namespace llvm {
|
|||||||
/// Construct an ArrayRef from a std::vector.
|
/// Construct an ArrayRef from a std::vector.
|
||||||
template<typename A>
|
template<typename A>
|
||||||
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
|
/*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.
|
/// Construct an ArrayRef from a C array.
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
@ -120,14 +120,18 @@ namespace llvm {
|
|||||||
return Data[Length-1];
|
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.
|
/// equals - Check for element-wise equality.
|
||||||
bool equals(ArrayRef RHS) const {
|
bool equals(ArrayRef RHS) const {
|
||||||
if (Length != RHS.Length)
|
if (Length != RHS.Length)
|
||||||
return false;
|
return false;
|
||||||
for (size_type i = 0; i != Length; i++)
|
return std::equal(begin(), end(), RHS.begin());
|
||||||
if (Data[i] != RHS.Data[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// slice(n) - Chop off the first N elements of the array.
|
/// slice(n) - Chop off the first N elements of the array.
|
||||||
@ -143,6 +147,12 @@ namespace llvm {
|
|||||||
return ArrayRef<T>(data()+N, M);
|
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
|
/// @name Operator Overloads
|
||||||
/// @{
|
/// @{
|
||||||
@ -213,7 +223,7 @@ namespace llvm {
|
|||||||
|
|
||||||
/// Construct an MutableArrayRef from a C array.
|
/// Construct an MutableArrayRef from a C array.
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
/*implicit*/ MutableArrayRef(T (&Arr)[N])
|
/*implicit*/ LLVM_CONSTEXPR MutableArrayRef(T (&Arr)[N])
|
||||||
: ArrayRef<T>(Arr) {}
|
: ArrayRef<T>(Arr) {}
|
||||||
|
|
||||||
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
|
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
|
||||||
|
@ -34,6 +34,7 @@ class BitVector {
|
|||||||
unsigned Capacity; // Size of allocated memory in BitWord.
|
unsigned Capacity; // Size of allocated memory in BitWord.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef unsigned size_type;
|
||||||
// Encapsulation of a single bit.
|
// Encapsulation of a single bit.
|
||||||
class reference {
|
class reference {
|
||||||
friend class BitVector;
|
friend class BitVector;
|
||||||
@ -58,21 +59,21 @@ public:
|
|||||||
|
|
||||||
reference& operator=(bool t) {
|
reference& operator=(bool t) {
|
||||||
if (t)
|
if (t)
|
||||||
*WordRef |= 1L << BitPos;
|
*WordRef |= BitWord(1) << BitPos;
|
||||||
else
|
else
|
||||||
*WordRef &= ~(1L << BitPos);
|
*WordRef &= ~(BitWord(1) << BitPos);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const {
|
operator bool() const {
|
||||||
return ((*WordRef) & (1L << BitPos)) ? true : false;
|
return ((*WordRef) & (BitWord(1) << BitPos)) ? true : false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// BitVector default ctor - Creates an empty bitvector.
|
/// BitVector default ctor - Creates an empty bitvector.
|
||||||
BitVector() : Size(0), Capacity(0) {
|
BitVector() : Size(0), Capacity(0) {
|
||||||
Bits = 0;
|
Bits = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BitVector ctor - Creates a bitvector of specified number of bits. All
|
/// BitVector ctor - Creates a bitvector of specified number of bits. All
|
||||||
@ -88,7 +89,7 @@ public:
|
|||||||
/// BitVector copy ctor.
|
/// BitVector copy ctor.
|
||||||
BitVector(const BitVector &RHS) : Size(RHS.size()) {
|
BitVector(const BitVector &RHS) : Size(RHS.size()) {
|
||||||
if (Size == 0) {
|
if (Size == 0) {
|
||||||
Bits = 0;
|
Bits = nullptr;
|
||||||
Capacity = 0;
|
Capacity = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -98,12 +99,10 @@ public:
|
|||||||
std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord));
|
std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
BitVector(BitVector &&RHS)
|
BitVector(BitVector &&RHS)
|
||||||
: Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
|
: Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
|
||||||
RHS.Bits = 0;
|
RHS.Bits = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
~BitVector() {
|
~BitVector() {
|
||||||
std::free(Bits);
|
std::free(Bits);
|
||||||
@ -113,10 +112,10 @@ public:
|
|||||||
bool empty() const { return Size == 0; }
|
bool empty() const { return Size == 0; }
|
||||||
|
|
||||||
/// size - Returns the number of bits in this bitvector.
|
/// 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.
|
/// count - Returns the number of bits which are set.
|
||||||
unsigned count() const {
|
size_type count() const {
|
||||||
unsigned NumBits = 0;
|
unsigned NumBits = 0;
|
||||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
||||||
if (sizeof(BitWord) == 4)
|
if (sizeof(BitWord) == 4)
|
||||||
@ -240,7 +239,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
BitVector &set(unsigned Idx) {
|
BitVector &set(unsigned Idx) {
|
||||||
Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE);
|
Bits[Idx / BITWORD_SIZE] |= BitWord(1) << (Idx % BITWORD_SIZE);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +266,8 @@ public:
|
|||||||
Bits[I / BITWORD_SIZE] = ~0UL;
|
Bits[I / BITWORD_SIZE] = ~0UL;
|
||||||
|
|
||||||
BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1;
|
BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1;
|
||||||
Bits[I / BITWORD_SIZE] |= PostfixMask;
|
if (I < E)
|
||||||
|
Bits[I / BITWORD_SIZE] |= PostfixMask;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
BitVector &reset(unsigned Idx) {
|
BitVector &reset(unsigned Idx) {
|
||||||
Bits[Idx / BITWORD_SIZE] &= ~(1L << (Idx % BITWORD_SIZE));
|
Bits[Idx / BITWORD_SIZE] &= ~(BitWord(1) << (Idx % BITWORD_SIZE));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +305,8 @@ public:
|
|||||||
Bits[I / BITWORD_SIZE] = 0UL;
|
Bits[I / BITWORD_SIZE] = 0UL;
|
||||||
|
|
||||||
BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1;
|
BitWord PostfixMask = (1UL << (E % BITWORD_SIZE)) - 1;
|
||||||
Bits[I / BITWORD_SIZE] &= ~PostfixMask;
|
if (I < E)
|
||||||
|
Bits[I / BITWORD_SIZE] &= ~PostfixMask;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -318,7 +319,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
BitVector &flip(unsigned Idx) {
|
BitVector &flip(unsigned Idx) {
|
||||||
Bits[Idx / BITWORD_SIZE] ^= 1L << (Idx % BITWORD_SIZE);
|
Bits[Idx / BITWORD_SIZE] ^= BitWord(1) << (Idx % BITWORD_SIZE);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +331,7 @@ public:
|
|||||||
|
|
||||||
bool operator[](unsigned Idx) const {
|
bool operator[](unsigned Idx) const {
|
||||||
assert (Idx < Size && "Out-of-bounds Bit access.");
|
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;
|
return (Bits[Idx / BITWORD_SIZE] & Mask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,7 +460,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
const BitVector &operator=(BitVector &&RHS) {
|
const BitVector &operator=(BitVector &&RHS) {
|
||||||
if (this == &RHS) return *this;
|
if (this == &RHS) return *this;
|
||||||
|
|
||||||
@ -468,11 +468,10 @@ public:
|
|||||||
Size = RHS.Size;
|
Size = RHS.Size;
|
||||||
Capacity = RHS.Capacity;
|
Capacity = RHS.Capacity;
|
||||||
|
|
||||||
RHS.Bits = 0;
|
RHS.Bits = nullptr;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void swap(BitVector &RHS) {
|
void swap(BitVector &RHS) {
|
||||||
std::swap(Bits, RHS.Bits);
|
std::swap(Bits, RHS.Bits);
|
||||||
|
@ -43,6 +43,7 @@ protected:
|
|||||||
typedef std::pair<KeyT, ValueT> BucketT;
|
typedef std::pair<KeyT, ValueT> BucketT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef unsigned size_type;
|
||||||
typedef KeyT key_type;
|
typedef KeyT key_type;
|
||||||
typedef ValueT mapped_type;
|
typedef ValueT mapped_type;
|
||||||
typedef BucketT value_type;
|
typedef BucketT value_type;
|
||||||
@ -70,7 +71,7 @@ public:
|
|||||||
unsigned size() const { return getNumEntries(); }
|
unsigned size() const { return getNumEntries(); }
|
||||||
|
|
||||||
/// Grow the densemap so that it has at least Size buckets. Does not shrink
|
/// 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())
|
if (Size > getNumBuckets())
|
||||||
grow(Size);
|
grow(Size);
|
||||||
}
|
}
|
||||||
@ -99,10 +100,10 @@ public:
|
|||||||
setNumTombstones(0);
|
setNumTombstones(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// count - Return true if the specified key is in the map.
|
/// Return 1 if the specified key is in the map, 0 otherwise.
|
||||||
bool count(const KeyT &Val) const {
|
size_type count(const KeyT &Val) const {
|
||||||
const BucketT *TheBucket;
|
const BucketT *TheBucket;
|
||||||
return LookupBucketFor(Val, TheBucket);
|
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator find(const KeyT &Val) {
|
iterator find(const KeyT &Val) {
|
||||||
@ -161,7 +162,6 @@ public:
|
|||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
|
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.
|
// 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
|
// If the key is already in the map, it returns false and doesn't update the
|
||||||
// value.
|
// value.
|
||||||
@ -177,8 +177,7 @@ public:
|
|||||||
TheBucket);
|
TheBucket);
|
||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
|
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// insert - Range insertion of pairs.
|
/// insert - Range insertion of pairs.
|
||||||
template<typename InputIt>
|
template<typename InputIt>
|
||||||
void insert(InputIt I, InputIt E) {
|
void insert(InputIt I, InputIt E) {
|
||||||
@ -218,7 +217,6 @@ public:
|
|||||||
return FindAndConstruct(Key).second;
|
return FindAndConstruct(Key).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
value_type& FindAndConstruct(KeyT &&Key) {
|
value_type& FindAndConstruct(KeyT &&Key) {
|
||||||
BucketT *TheBucket;
|
BucketT *TheBucket;
|
||||||
if (LookupBucketFor(Key, TheBucket))
|
if (LookupBucketFor(Key, TheBucket))
|
||||||
@ -230,7 +228,6 @@ public:
|
|||||||
ValueT &operator[](KeyT &&Key) {
|
ValueT &operator[](KeyT &&Key) {
|
||||||
return FindAndConstruct(std::move(Key)).second;
|
return FindAndConstruct(std::move(Key)).second;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// isPointerIntoBucketsArray - Return true if the specified pointer points
|
/// isPointerIntoBucketsArray - Return true if the specified pointer points
|
||||||
/// somewhere into the DenseMap's array of buckets (i.e. either to a key or
|
/// 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);
|
bool FoundVal = LookupBucketFor(B->first, DestBucket);
|
||||||
(void)FoundVal; // silence warning.
|
(void)FoundVal; // silence warning.
|
||||||
assert(!FoundVal && "Key already in new map?");
|
assert(!FoundVal && "Key already in new map?");
|
||||||
DestBucket->first = llvm_move(B->first);
|
DestBucket->first = std::move(B->first);
|
||||||
new (&DestBucket->second) ValueT(llvm_move(B->second));
|
new (&DestBucket->second) ValueT(std::move(B->second));
|
||||||
incrementNumEntries();
|
incrementNumEntries();
|
||||||
|
|
||||||
// Free the value.
|
// Free the value.
|
||||||
@ -403,7 +400,6 @@ private:
|
|||||||
return TheBucket;
|
return TheBucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
|
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
|
||||||
BucketT *TheBucket) {
|
BucketT *TheBucket) {
|
||||||
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
|
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
|
||||||
@ -420,7 +416,6 @@ private:
|
|||||||
new (&TheBucket->second) ValueT(std::move(Value));
|
new (&TheBucket->second) ValueT(std::move(Value));
|
||||||
return TheBucket;
|
return TheBucket;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
|
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
|
// 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();
|
const unsigned NumBuckets = getNumBuckets();
|
||||||
|
|
||||||
if (NumBuckets == 0) {
|
if (NumBuckets == 0) {
|
||||||
FoundBucket = 0;
|
FoundBucket = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FoundTombstone - Keep track of whether we find a tombstone while probing.
|
// 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 EmptyKey = getEmptyKey();
|
||||||
const KeyT TombstoneKey = getTombstoneKey();
|
const KeyT TombstoneKey = getTombstoneKey();
|
||||||
assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
|
assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
|
||||||
@ -555,12 +550,10 @@ public:
|
|||||||
copyFrom(other);
|
copyFrom(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
DenseMap(DenseMap &&other) : BaseT() {
|
DenseMap(DenseMap &&other) : BaseT() {
|
||||||
init(0);
|
init(0);
|
||||||
swap(other);
|
swap(other);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename InputIt>
|
template<typename InputIt>
|
||||||
DenseMap(const InputIt &I, const InputIt &E) {
|
DenseMap(const InputIt &I, const InputIt &E) {
|
||||||
@ -585,7 +578,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
DenseMap& operator=(DenseMap &&other) {
|
DenseMap& operator=(DenseMap &&other) {
|
||||||
this->destroyAll();
|
this->destroyAll();
|
||||||
operator delete(Buckets);
|
operator delete(Buckets);
|
||||||
@ -593,7 +585,6 @@ public:
|
|||||||
swap(other);
|
swap(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void copyFrom(const DenseMap& other) {
|
void copyFrom(const DenseMap& other) {
|
||||||
this->destroyAll();
|
this->destroyAll();
|
||||||
@ -675,7 +666,7 @@ private:
|
|||||||
bool allocateBuckets(unsigned Num) {
|
bool allocateBuckets(unsigned Num) {
|
||||||
NumBuckets = Num;
|
NumBuckets = Num;
|
||||||
if (NumBuckets == 0) {
|
if (NumBuckets == 0) {
|
||||||
Buckets = 0;
|
Buckets = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,12 +710,10 @@ public:
|
|||||||
copyFrom(other);
|
copyFrom(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
SmallDenseMap(SmallDenseMap &&other) : BaseT() {
|
SmallDenseMap(SmallDenseMap &&other) : BaseT() {
|
||||||
init(0);
|
init(0);
|
||||||
swap(other);
|
swap(other);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename InputIt>
|
template<typename InputIt>
|
||||||
SmallDenseMap(const InputIt &I, const InputIt &E) {
|
SmallDenseMap(const InputIt &I, const InputIt &E) {
|
||||||
@ -765,10 +754,10 @@ public:
|
|||||||
// Swap separately and handle any assymetry.
|
// Swap separately and handle any assymetry.
|
||||||
std::swap(LHSB->first, RHSB->first);
|
std::swap(LHSB->first, RHSB->first);
|
||||||
if (hasLHSValue) {
|
if (hasLHSValue) {
|
||||||
new (&RHSB->second) ValueT(llvm_move(LHSB->second));
|
new (&RHSB->second) ValueT(std::move(LHSB->second));
|
||||||
LHSB->second.~ValueT();
|
LHSB->second.~ValueT();
|
||||||
} else if (hasRHSValue) {
|
} else if (hasRHSValue) {
|
||||||
new (&LHSB->second) ValueT(llvm_move(RHSB->second));
|
new (&LHSB->second) ValueT(std::move(RHSB->second));
|
||||||
RHSB->second.~ValueT();
|
RHSB->second.~ValueT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -784,7 +773,7 @@ public:
|
|||||||
SmallDenseMap &LargeSide = Small ? RHS : *this;
|
SmallDenseMap &LargeSide = Small ? RHS : *this;
|
||||||
|
|
||||||
// First stash the large side's rep and move the small side across.
|
// 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.getLargeRep()->~LargeRep();
|
||||||
LargeSide.Small = true;
|
LargeSide.Small = true;
|
||||||
// This is similar to the standard move-from-old-buckets, but the bucket
|
// 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) {
|
for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
|
||||||
BucketT *NewB = &LargeSide.getInlineBuckets()[i],
|
BucketT *NewB = &LargeSide.getInlineBuckets()[i],
|
||||||
*OldB = &SmallSide.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();
|
OldB->first.~KeyT();
|
||||||
if (!KeyInfoT::isEqual(NewB->first, EmptyKey) &&
|
if (!KeyInfoT::isEqual(NewB->first, EmptyKey) &&
|
||||||
!KeyInfoT::isEqual(NewB->first, TombstoneKey)) {
|
!KeyInfoT::isEqual(NewB->first, TombstoneKey)) {
|
||||||
new (&NewB->second) ValueT(llvm_move(OldB->second));
|
new (&NewB->second) ValueT(std::move(OldB->second));
|
||||||
OldB->second.~ValueT();
|
OldB->second.~ValueT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,7 +795,7 @@ public:
|
|||||||
// The hard part of moving the small buckets across is done, just move
|
// The hard part of moving the small buckets across is done, just move
|
||||||
// the TmpRep into its new home.
|
// the TmpRep into its new home.
|
||||||
SmallSide.Small = false;
|
SmallSide.Small = false;
|
||||||
new (SmallSide.getLargeRep()) LargeRep(llvm_move(TmpRep));
|
new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep));
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallDenseMap& operator=(const SmallDenseMap& other) {
|
SmallDenseMap& operator=(const SmallDenseMap& other) {
|
||||||
@ -814,7 +803,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
SmallDenseMap& operator=(SmallDenseMap &&other) {
|
SmallDenseMap& operator=(SmallDenseMap &&other) {
|
||||||
this->destroyAll();
|
this->destroyAll();
|
||||||
deallocateBuckets();
|
deallocateBuckets();
|
||||||
@ -822,7 +810,6 @@ public:
|
|||||||
swap(other);
|
swap(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void copyFrom(const SmallDenseMap& other) {
|
void copyFrom(const SmallDenseMap& other) {
|
||||||
this->destroyAll();
|
this->destroyAll();
|
||||||
@ -830,7 +817,7 @@ public:
|
|||||||
Small = true;
|
Small = true;
|
||||||
if (other.getNumBuckets() > InlineBuckets) {
|
if (other.getNumBuckets() > InlineBuckets) {
|
||||||
Small = false;
|
Small = false;
|
||||||
allocateBuckets(other.getNumBuckets());
|
new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets()));
|
||||||
}
|
}
|
||||||
this->BaseT::copyFrom(other);
|
this->BaseT::copyFrom(other);
|
||||||
}
|
}
|
||||||
@ -866,8 +853,8 @@ public:
|
|||||||
!KeyInfoT::isEqual(P->first, TombstoneKey)) {
|
!KeyInfoT::isEqual(P->first, TombstoneKey)) {
|
||||||
assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&
|
assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&
|
||||||
"Too many inline buckets!");
|
"Too many inline buckets!");
|
||||||
new (&TmpEnd->first) KeyT(llvm_move(P->first));
|
new (&TmpEnd->first) KeyT(std::move(P->first));
|
||||||
new (&TmpEnd->second) ValueT(llvm_move(P->second));
|
new (&TmpEnd->second) ValueT(std::move(P->second));
|
||||||
++TmpEnd;
|
++TmpEnd;
|
||||||
P->second.~ValueT();
|
P->second.~ValueT();
|
||||||
}
|
}
|
||||||
@ -882,7 +869,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LargeRep OldRep = llvm_move(*getLargeRep());
|
LargeRep OldRep = std::move(*getLargeRep());
|
||||||
getLargeRep()->~LargeRep();
|
getLargeRep()->~LargeRep();
|
||||||
if (AtLeast <= InlineBuckets) {
|
if (AtLeast <= InlineBuckets) {
|
||||||
Small = true;
|
Small = true;
|
||||||
@ -991,14 +978,15 @@ class DenseMapIterator {
|
|||||||
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>;
|
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>;
|
||||||
public:
|
public:
|
||||||
typedef ptrdiff_t difference_type;
|
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 *pointer;
|
||||||
typedef value_type &reference;
|
typedef value_type &reference;
|
||||||
typedef std::forward_iterator_tag iterator_category;
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
private:
|
private:
|
||||||
pointer Ptr, End;
|
pointer Ptr, End;
|
||||||
public:
|
public:
|
||||||
DenseMapIterator() : Ptr(0), End(0) {}
|
DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
|
||||||
|
|
||||||
DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
|
DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
|
||||||
: Ptr(Pos), End(E) {
|
: Ptr(Pos), End(E) {
|
||||||
|
@ -27,11 +27,14 @@ class DenseSet {
|
|||||||
typedef DenseMap<ValueT, char, ValueInfoT> MapTy;
|
typedef DenseMap<ValueT, char, ValueInfoT> MapTy;
|
||||||
MapTy TheMap;
|
MapTy TheMap;
|
||||||
public:
|
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) {}
|
explicit DenseSet(unsigned NumInitBuckets = 0) : TheMap(NumInitBuckets) {}
|
||||||
|
|
||||||
bool empty() const { return TheMap.empty(); }
|
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(); }
|
size_t getMemorySize() const { return TheMap.getMemorySize(); }
|
||||||
|
|
||||||
/// Grow the DenseSet so that it has at least Size buckets. Will not shrink
|
/// Grow the DenseSet so that it has at least Size buckets. Will not shrink
|
||||||
@ -42,7 +45,8 @@ public:
|
|||||||
TheMap.clear();
|
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);
|
return TheMap.count(V);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,11 +58,6 @@ public:
|
|||||||
TheMap.swap(RHS.TheMap);
|
TheMap.swap(RHS.TheMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
DenseSet &operator=(const DenseSet &RHS) {
|
|
||||||
TheMap = RHS.TheMap;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterators.
|
// Iterators.
|
||||||
|
|
||||||
class Iterator {
|
class Iterator {
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#ifndef LLVM_ADT_DEPTHFIRSTITERATOR_H
|
#ifndef LLVM_ADT_DEPTHFIRSTITERATOR_H
|
||||||
#define LLVM_ADT_DEPTHFIRSTITERATOR_H
|
#define LLVM_ADT_DEPTHFIRSTITERATOR_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/iterator_range.h"
|
||||||
#include "llvm/ADT/GraphTraits.h"
|
#include "llvm/ADT/GraphTraits.h"
|
||||||
#include "llvm/ADT/PointerIntPair.h"
|
#include "llvm/ADT/PointerIntPair.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
@ -207,6 +208,12 @@ df_iterator<T> df_end(const T& G) {
|
|||||||
return df_iterator<T>::end(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...
|
// Provide global definitions of external depth first iterators...
|
||||||
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
|
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
|
||||||
struct df_ext_iterator : public df_iterator<T, SetTy, true> {
|
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));
|
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...
|
// Provide global definitions of external inverse depth first iterators...
|
||||||
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
|
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
|
||||||
struct idf_ext_iterator : public idf_iterator<T, SetTy, true> {
|
struct idf_ext_iterator : public idf_iterator<T, SetTy, true> {
|
||||||
|
@ -86,14 +86,14 @@ class EquivalenceClasses {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setNext(const ECValue *NewNext) const {
|
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());
|
Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
|
ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
|
||||||
Data(RHS.Data) {
|
Data(RHS.Data) {
|
||||||
// Only support copying of singleton nodes.
|
// 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; }
|
bool operator<(const ECValue &UFN) const { return Data < UFN.Data; }
|
||||||
@ -147,10 +147,10 @@ public:
|
|||||||
class member_iterator;
|
class member_iterator;
|
||||||
member_iterator member_begin(iterator I) const {
|
member_iterator member_begin(iterator I) const {
|
||||||
// Only leaders provide anything to iterate over.
|
// 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 {
|
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
|
/// findValue - Return an iterator to the specified value. If it does not
|
||||||
@ -249,16 +249,15 @@ public:
|
|||||||
|
|
||||||
explicit member_iterator() {}
|
explicit member_iterator() {}
|
||||||
explicit member_iterator(const ECValue *N) : Node(N) {}
|
explicit member_iterator(const ECValue *N) : Node(N) {}
|
||||||
member_iterator(const member_iterator &I) : Node(I.Node) {}
|
|
||||||
|
|
||||||
reference operator*() const {
|
reference operator*() const {
|
||||||
assert(Node != 0 && "Dereferencing end()!");
|
assert(Node != nullptr && "Dereferencing end()!");
|
||||||
return Node->getData();
|
return Node->getData();
|
||||||
}
|
}
|
||||||
reference operator->() const { return operator*(); }
|
reference operator->() const { return operator*(); }
|
||||||
|
|
||||||
member_iterator &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();
|
Node = Node->getNext();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/Support/Allocator.h"
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class APFloat;
|
class APFloat;
|
||||||
class APInt;
|
class APInt;
|
||||||
class BumpPtrAllocator;
|
|
||||||
|
|
||||||
/// This folding set used for two purposes:
|
/// This folding set used for two purposes:
|
||||||
/// 1. Given information about a node we want to create, look up the unique
|
/// 1. Given information about a node we want to create, look up the unique
|
||||||
@ -137,7 +137,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Node() : NextInFoldingSetBucket(0) {}
|
Node() : NextInFoldingSetBucket(nullptr) {}
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
void *getNextInBucket() const { return NextInFoldingSetBucket; }
|
void *getNextInBucket() const { return NextInFoldingSetBucket; }
|
||||||
@ -269,7 +269,7 @@ class FoldingSetNodeIDRef {
|
|||||||
const unsigned *Data;
|
const unsigned *Data;
|
||||||
size_t Size;
|
size_t Size;
|
||||||
public:
|
public:
|
||||||
FoldingSetNodeIDRef() : Data(0), Size(0) {}
|
FoldingSetNodeIDRef() : Data(nullptr), Size(0) {}
|
||||||
FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
|
FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
|
||||||
|
|
||||||
/// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
|
/// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
|
||||||
@ -278,6 +278,8 @@ public:
|
|||||||
|
|
||||||
bool operator==(FoldingSetNodeIDRef) const;
|
bool operator==(FoldingSetNodeIDRef) const;
|
||||||
|
|
||||||
|
bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
|
||||||
|
|
||||||
/// Used to compare the "ordering" of two nodes as defined by the
|
/// Used to compare the "ordering" of two nodes as defined by the
|
||||||
/// profiled bits and their ordering defined by memcmp().
|
/// profiled bits and their ordering defined by memcmp().
|
||||||
bool operator<(FoldingSetNodeIDRef) const;
|
bool operator<(FoldingSetNodeIDRef) const;
|
||||||
@ -331,6 +333,9 @@ public:
|
|||||||
bool operator==(const FoldingSetNodeID &RHS) const;
|
bool operator==(const FoldingSetNodeID &RHS) const;
|
||||||
bool operator==(const FoldingSetNodeIDRef 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
|
/// Used to compare the "ordering" of two nodes as defined by the
|
||||||
/// profiled bits and their ordering defined by memcmp().
|
/// profiled bits and their ordering defined by memcmp().
|
||||||
bool operator<(const FoldingSetNodeID &RHS) const;
|
bool operator<(const FoldingSetNodeID &RHS) const;
|
||||||
@ -391,20 +396,20 @@ template<class T> class FoldingSet : public FoldingSetImpl {
|
|||||||
private:
|
private:
|
||||||
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
||||||
/// way to convert nodes into a unique specifier.
|
/// 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);
|
T *TN = static_cast<T *>(N);
|
||||||
FoldingSetTrait<T>::Profile(*TN, ID);
|
FoldingSetTrait<T>::Profile(*TN, ID);
|
||||||
}
|
}
|
||||||
/// NodeEquals - Instantiations may optionally provide a way to compare a
|
/// NodeEquals - Instantiations may optionally provide a way to compare a
|
||||||
/// node with a specified ID.
|
/// node with a specified ID.
|
||||||
virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
|
bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
|
||||||
FoldingSetNodeID &TempID) const {
|
FoldingSetNodeID &TempID) const override {
|
||||||
T *TN = static_cast<T *>(N);
|
T *TN = static_cast<T *>(N);
|
||||||
return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
|
return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
|
||||||
}
|
}
|
||||||
/// ComputeNodeHash - Instantiations may optionally provide a way to compute a
|
/// ComputeNodeHash - Instantiations may optionally provide a way to compute a
|
||||||
/// hash value directly from a node.
|
/// 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);
|
T *TN = static_cast<T *>(N);
|
||||||
return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
|
return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
|
||||||
}
|
}
|
||||||
@ -468,20 +473,19 @@ private:
|
|||||||
|
|
||||||
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
||||||
/// way to convert nodes into a unique specifier.
|
/// way to convert nodes into a unique specifier.
|
||||||
virtual void GetNodeProfile(FoldingSetImpl::Node *N,
|
void GetNodeProfile(FoldingSetImpl::Node *N,
|
||||||
FoldingSetNodeID &ID) const {
|
FoldingSetNodeID &ID) const override {
|
||||||
T *TN = static_cast<T *>(N);
|
T *TN = static_cast<T *>(N);
|
||||||
ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context);
|
ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context);
|
||||||
}
|
}
|
||||||
virtual bool NodeEquals(FoldingSetImpl::Node *N,
|
bool NodeEquals(FoldingSetImpl::Node *N, const FoldingSetNodeID &ID,
|
||||||
const FoldingSetNodeID &ID, unsigned IDHash,
|
unsigned IDHash, FoldingSetNodeID &TempID) const override {
|
||||||
FoldingSetNodeID &TempID) const {
|
|
||||||
T *TN = static_cast<T *>(N);
|
T *TN = static_cast<T *>(N);
|
||||||
return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
|
return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
|
||||||
Context);
|
Context);
|
||||||
}
|
}
|
||||||
virtual unsigned ComputeNodeHash(FoldingSetImpl::Node *N,
|
unsigned ComputeNodeHash(FoldingSetImpl::Node *N,
|
||||||
FoldingSetNodeID &TempID) const {
|
FoldingSetNodeID &TempID) const override {
|
||||||
T *TN = static_cast<T *>(N);
|
T *TN = static_cast<T *>(N);
|
||||||
return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, Context);
|
return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, Context);
|
||||||
}
|
}
|
||||||
@ -790,6 +794,14 @@ template<typename T> struct FoldingSetTrait<T*> {
|
|||||||
ID.AddPointer(X);
|
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.
|
} // End of namespace llvm.
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,7 +45,6 @@
|
|||||||
#ifndef LLVM_ADT_HASHING_H
|
#ifndef LLVM_ADT_HASHING_H
|
||||||
#define LLVM_ADT_HASHING_H
|
#define LLVM_ADT_HASHING_H
|
||||||
|
|
||||||
#include "llvm/ADT/STLExtras.h"
|
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
#include "llvm/Support/Host.h"
|
#include "llvm/Support/Host.h"
|
||||||
#include "llvm/Support/SwapByteOrder.h"
|
#include "llvm/Support/SwapByteOrder.h"
|
||||||
@ -109,7 +108,8 @@ public:
|
|||||||
/// differing argument types even if they would implicit promote to a common
|
/// differing argument types even if they would implicit promote to a common
|
||||||
/// type without changing the value.
|
/// type without changing the value.
|
||||||
template <typename T>
|
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.
|
/// \brief Compute a hash_code for a pointer's address.
|
||||||
///
|
///
|
||||||
@ -152,7 +152,7 @@ inline uint64_t fetch64(const char *p) {
|
|||||||
uint64_t result;
|
uint64_t result;
|
||||||
memcpy(&result, p, sizeof(result));
|
memcpy(&result, p, sizeof(result));
|
||||||
if (sys::IsBigEndianHost)
|
if (sys::IsBigEndianHost)
|
||||||
return sys::SwapByteOrder(result);
|
sys::swapByteOrder(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ inline uint32_t fetch32(const char *p) {
|
|||||||
uint32_t result;
|
uint32_t result;
|
||||||
memcpy(&result, p, sizeof(result));
|
memcpy(&result, p, sizeof(result));
|
||||||
if (sys::IsBigEndianHost)
|
if (sys::IsBigEndianHost)
|
||||||
return sys::SwapByteOrder(result);
|
sys::swapByteOrder(result);
|
||||||
return 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.
|
/// keeps 56 bytes of arbitrary state.
|
||||||
struct hash_state {
|
struct hash_state {
|
||||||
uint64_t h0, h1, h2, h3, h4, h5, h6;
|
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
|
/// \brief Create a new hash_state structure and initialize it based on the
|
||||||
/// seed and the first 64-byte chunk.
|
/// seed and the first 64-byte chunk.
|
||||||
@ -273,7 +272,7 @@ struct hash_state {
|
|||||||
static hash_state create(const char *s, uint64_t seed) {
|
static hash_state create(const char *s, uint64_t seed) {
|
||||||
hash_state state = {
|
hash_state state = {
|
||||||
0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
|
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.h6 = hash_16_bytes(state.h4, state.h5);
|
||||||
state.mix(s);
|
state.mix(s);
|
||||||
return state;
|
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
|
// 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.
|
// support user-defined types which happen to satisfy this property.
|
||||||
template <typename T> struct is_hashable_data
|
template <typename T> struct is_hashable_data
|
||||||
: integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
: std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
||||||
is_pointer<T>::value) &&
|
std::is_pointer<T>::value) &&
|
||||||
64 % sizeof(T) == 0)> {};
|
64 % sizeof(T) == 0)> {};
|
||||||
|
|
||||||
// Special case std::pair to detect when both types are viable and when there
|
// 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
|
// 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
|
// std::pair isn't truly POD, but it's close enough in all reasonable
|
||||||
// implementations for our use case of hashing the underlying data.
|
// implementations for our use case of hashing the underlying data.
|
||||||
template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
||||||
: integral_constant<bool, (is_hashable_data<T>::value &&
|
: std::integral_constant<bool, (is_hashable_data<T>::value &&
|
||||||
is_hashable_data<U>::value &&
|
is_hashable_data<U>::value &&
|
||||||
(sizeof(T) + sizeof(U)) ==
|
(sizeof(T) + sizeof(U)) ==
|
||||||
sizeof(std::pair<T, U>))> {};
|
sizeof(std::pair<T, U>))> {};
|
||||||
|
|
||||||
/// \brief Helper to get the hashable data representation for a type.
|
/// \brief Helper to get the hashable data representation for a type.
|
||||||
/// This variant is enabled when the type itself can be used.
|
/// This variant is enabled when the type itself can be used.
|
||||||
template <typename T>
|
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) {
|
get_hashable_data(const T &value) {
|
||||||
return 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
|
/// This variant is enabled when we must first call hash_value and use the
|
||||||
/// result as our data.
|
/// result as our data.
|
||||||
template <typename T>
|
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) {
|
get_hashable_data(const T &value) {
|
||||||
using ::llvm::hash_value;
|
using ::llvm::hash_value;
|
||||||
return hash_value(value);
|
return hash_value(value);
|
||||||
@ -411,7 +410,7 @@ template <typename InputIteratorT>
|
|||||||
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||||
const size_t seed = get_execution_seed();
|
const size_t seed = get_execution_seed();
|
||||||
char buffer[64], *buffer_ptr = buffer;
|
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,
|
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||||
get_hashable_data(*first)))
|
get_hashable_data(*first)))
|
||||||
++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
|
/// are stored in contiguous memory, this routine avoids copying each value
|
||||||
/// and directly reads from the underlying memory.
|
/// and directly reads from the underlying memory.
|
||||||
template <typename ValueT>
|
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) {
|
hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||||
const size_t seed = get_execution_seed();
|
const size_t seed = get_execution_seed();
|
||||||
const char *s_begin = reinterpret_cast<const char *>(first);
|
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
|
// Declared and documented above, but defined here so that any of the hashing
|
||||||
// infrastructure is available.
|
// infrastructure is available.
|
||||||
template <typename T>
|
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) {
|
hash_value(T value) {
|
||||||
return ::llvm::hashing::detail::hash_integer_value(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;
|
if (T) return &T->getValue().second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
|
/// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
|
||||||
/// which key is the highest in the ordering of keys in the map. This
|
/// which key is the highest in the ordering of keys in the map. This
|
||||||
/// method returns NULL if the map is empty.
|
/// method returns NULL if the map is empty.
|
||||||
value_type* getMaxElement() const {
|
value_type* getMaxElement() const {
|
||||||
return Root ? &(Root->getMaxElement()->getValue()) : 0;
|
return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===--------------------------------------------------===//
|
//===--------------------------------------------------===//
|
||||||
|
@ -81,7 +81,7 @@ public:
|
|||||||
else
|
else
|
||||||
T = T->getRight();
|
T = T->getRight();
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getMaxElement - Find the subtree associated with the highest ranged
|
/// getMaxElement - Find the subtree associated with the highest ranged
|
||||||
@ -242,9 +242,9 @@ private:
|
|||||||
/// ImutAVLFactory.
|
/// ImutAVLFactory.
|
||||||
ImutAVLTree(Factory *f, ImutAVLTree* l, ImutAVLTree* r, value_type_ref v,
|
ImutAVLTree(Factory *f, ImutAVLTree* l, ImutAVLTree* r, value_type_ref v,
|
||||||
unsigned height)
|
unsigned height)
|
||||||
: factory(f), left(l), right(r), prev(0), next(0), height(height),
|
: factory(f), left(l), right(r), prev(nullptr), next(nullptr),
|
||||||
IsMutable(true), IsDigestCached(false), IsCanonicalized(0),
|
height(height), IsMutable(true), IsDigestCached(false),
|
||||||
value(v), digest(0), refCount(0)
|
IsCanonicalized(0), value(v), digest(0), refCount(0)
|
||||||
{
|
{
|
||||||
if (left) left->retain();
|
if (left) left->retain();
|
||||||
if (right) right->retain();
|
if (right) right->retain();
|
||||||
@ -411,7 +411,7 @@ public:
|
|||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeTy* getEmptyTree() const { return NULL; }
|
TreeTy* getEmptyTree() const { return nullptr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -607,7 +607,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
TreeTy *getCanonicalTree(TreeTy *TNew) {
|
TreeTy *getCanonicalTree(TreeTy *TNew) {
|
||||||
if (!TNew)
|
if (!TNew)
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
if (TNew->IsCanonicalized)
|
if (TNew->IsCanonicalized)
|
||||||
return TNew;
|
return TNew;
|
||||||
@ -619,7 +619,7 @@ public:
|
|||||||
do {
|
do {
|
||||||
if (!entry)
|
if (!entry)
|
||||||
break;
|
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')
|
// Compare the Contents('T') with Contents('TNew')
|
||||||
typename TreeTy::iterator TI = T->begin(), TE = T->end();
|
typename TreeTy::iterator TI = T->begin(), TE = T->end();
|
||||||
if (!compareTreeWithSection(TNew, TI, TE))
|
if (!compareTreeWithSection(TNew, TI, TE))
|
||||||
@ -696,12 +696,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const _Self& x) const {
|
inline bool operator==(const _Self& x) const {
|
||||||
if (stack.size() != x.stack.size())
|
return stack == x.stack;
|
||||||
return false;
|
|
||||||
for (unsigned i = 0 ; i < stack.size(); i++)
|
|
||||||
if (stack[i] != x.stack[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||||
|
@ -1177,7 +1177,7 @@ branchRoot(unsigned Position) {
|
|||||||
if (Nodes == 1)
|
if (Nodes == 1)
|
||||||
size[0] = rootSize;
|
size[0] = rootSize;
|
||||||
else
|
else
|
||||||
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, NULL, size,
|
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, nullptr, size,
|
||||||
Position, true);
|
Position, true);
|
||||||
|
|
||||||
// Allocate new nodes.
|
// Allocate new nodes.
|
||||||
@ -1218,7 +1218,7 @@ splitRoot(unsigned Position) {
|
|||||||
if (Nodes == 1)
|
if (Nodes == 1)
|
||||||
Size[0] = rootSize;
|
Size[0] = rootSize;
|
||||||
else
|
else
|
||||||
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, NULL, Size,
|
NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, nullptr, Size,
|
||||||
Position, true);
|
Position, true);
|
||||||
|
|
||||||
// Allocate new nodes.
|
// Allocate new nodes.
|
||||||
@ -1346,7 +1346,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// const_iterator - Create an iterator that isn't pointing anywhere.
|
/// 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
|
/// setMap - Change the map iterated over. This call must be followed by a
|
||||||
/// call to goToBegin(), goToEnd(), or find()
|
/// call to goToBegin(), goToEnd(), or find()
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -88,6 +89,31 @@ namespace llvm {
|
|||||||
static void retain(T *obj) { obj->Retain(); }
|
static void retain(T *obj) { obj->Retain(); }
|
||||||
static void release(T *obj) { obj->Release(); }
|
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"
|
/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
|
||||||
@ -109,11 +135,11 @@ namespace llvm {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class IntrusiveRefCntPtr {
|
class IntrusiveRefCntPtr {
|
||||||
T* Obj;
|
T* Obj;
|
||||||
typedef IntrusiveRefCntPtr this_type;
|
|
||||||
public:
|
public:
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
|
|
||||||
explicit IntrusiveRefCntPtr() : Obj(0) {}
|
explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
|
||||||
|
|
||||||
IntrusiveRefCntPtr(T* obj) : Obj(obj) {
|
IntrusiveRefCntPtr(T* obj) : Obj(obj) {
|
||||||
retain();
|
retain();
|
||||||
@ -123,20 +149,18 @@ namespace llvm {
|
|||||||
retain();
|
retain();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
|
IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
|
||||||
S.Obj = 0;
|
S.Obj = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X>
|
||||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.getPtr()) {
|
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
|
||||||
S.Obj = 0;
|
S.Obj = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class X>
|
template <class X>
|
||||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
|
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
|
||||||
: Obj(S.getPtr()) {
|
: Obj(S.get()) {
|
||||||
retain();
|
retain();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,12 +175,9 @@ namespace llvm {
|
|||||||
|
|
||||||
T* operator->() const { return Obj; }
|
T* operator->() const { return Obj; }
|
||||||
|
|
||||||
T* getPtr() const { return Obj; }
|
T* get() const { return Obj; }
|
||||||
|
|
||||||
typedef T* (IntrusiveRefCntPtr::*unspecified_bool_type) () const;
|
LLVM_EXPLICIT operator bool() const { return Obj; }
|
||||||
operator unspecified_bool_type() const {
|
|
||||||
return Obj == 0 ? 0 : &IntrusiveRefCntPtr::getPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap(IntrusiveRefCntPtr& other) {
|
void swap(IntrusiveRefCntPtr& other) {
|
||||||
T* tmp = other.Obj;
|
T* tmp = other.Obj;
|
||||||
@ -166,7 +187,7 @@ namespace llvm {
|
|||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
release();
|
release();
|
||||||
Obj = 0;
|
Obj = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetWithoutRelease() {
|
void resetWithoutRelease() {
|
||||||
@ -182,42 +203,62 @@ namespace llvm {
|
|||||||
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
||||||
const IntrusiveRefCntPtr<U>& B)
|
const IntrusiveRefCntPtr<U>& B)
|
||||||
{
|
{
|
||||||
return A.getPtr() == B.getPtr();
|
return A.get() == B.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
||||||
const IntrusiveRefCntPtr<U>& B)
|
const IntrusiveRefCntPtr<U>& B)
|
||||||
{
|
{
|
||||||
return A.getPtr() != B.getPtr();
|
return A.get() != B.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
||||||
U* B)
|
U* B)
|
||||||
{
|
{
|
||||||
return A.getPtr() == B;
|
return A.get() == B;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
||||||
U* B)
|
U* B)
|
||||||
{
|
{
|
||||||
return A.getPtr() != B;
|
return A.get() != B;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
inline bool operator==(T* A,
|
inline bool operator==(T* A,
|
||||||
const IntrusiveRefCntPtr<U>& B)
|
const IntrusiveRefCntPtr<U>& B)
|
||||||
{
|
{
|
||||||
return A == B.getPtr();
|
return A == B.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
inline bool operator!=(T* A,
|
inline bool operator!=(T* A,
|
||||||
const IntrusiveRefCntPtr<U>& B)
|
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> > {
|
template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
|
||||||
typedef T* SimpleType;
|
typedef T* SimpleType;
|
||||||
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
|
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
|
||||||
return Val.getPtr();
|
return Val.get();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
|
template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
|
||||||
typedef /*const*/ T* SimpleType;
|
typedef /*const*/ T* SimpleType;
|
||||||
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
|
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
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -17,9 +17,7 @@
|
|||||||
#ifndef LLVM_ADT_MAPVECTOR_H
|
#ifndef LLVM_ADT_MAPVECTOR_H
|
||||||
#define LLVM_ADT_MAPVECTOR_H
|
#define LLVM_ADT_MAPVECTOR_H
|
||||||
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -31,7 +29,7 @@ template<typename KeyT, typename ValueT,
|
|||||||
typename MapType = llvm::DenseMap<KeyT, unsigned>,
|
typename MapType = llvm::DenseMap<KeyT, unsigned>,
|
||||||
typename VectorType = std::vector<std::pair<KeyT, ValueT> > >
|
typename VectorType = std::vector<std::pair<KeyT, ValueT> > >
|
||||||
class MapVector {
|
class MapVector {
|
||||||
typedef typename VectorType::size_type SizeType;
|
typedef typename VectorType::size_type size_type;
|
||||||
|
|
||||||
MapType Map;
|
MapType Map;
|
||||||
VectorType Vector;
|
VectorType Vector;
|
||||||
@ -40,7 +38,7 @@ public:
|
|||||||
typedef typename VectorType::iterator iterator;
|
typedef typename VectorType::iterator iterator;
|
||||||
typedef typename VectorType::const_iterator const_iterator;
|
typedef typename VectorType::const_iterator const_iterator;
|
||||||
|
|
||||||
SizeType size() const {
|
size_type size() const {
|
||||||
return Vector.size();
|
return Vector.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,12 +95,12 @@ public:
|
|||||||
if (Result.second) {
|
if (Result.second) {
|
||||||
Vector.push_back(std::make_pair(KV.first, KV.second));
|
Vector.push_back(std::make_pair(KV.first, KV.second));
|
||||||
I = Vector.size() - 1;
|
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);
|
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);
|
typename MapType::const_iterator Pos = Map.find(Key);
|
||||||
return Pos == Map.end()? 0 : 1;
|
return Pos == Map.end()? 0 : 1;
|
||||||
}
|
}
|
||||||
@ -125,8 +123,59 @@ public:
|
|||||||
Map.erase(Pos);
|
Map.erase(Pos);
|
||||||
Vector.pop_back();
|
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
|
#endif
|
||||||
|
@ -17,13 +17,10 @@
|
|||||||
#define LLVM_ADT_OPTIONAL_H
|
#define LLVM_ADT_OPTIONAL_H
|
||||||
|
|
||||||
#include "llvm/ADT/None.h"
|
#include "llvm/ADT/None.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
#include "llvm/Support/AlignOf.h"
|
#include "llvm/Support/AlignOf.h"
|
||||||
|
#include "llvm/Support/Compiler.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -42,7 +39,6 @@ public:
|
|||||||
new (storage.buffer) T(*O);
|
new (storage.buffer) T(*O);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
Optional(T &&y) : hasVal(true) {
|
Optional(T &&y) : hasVal(true) {
|
||||||
new (storage.buffer) T(std::forward<T>(y));
|
new (storage.buffer) T(std::forward<T>(y));
|
||||||
}
|
}
|
||||||
@ -70,7 +66,6 @@ public:
|
|||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline Optional create(const T* y) {
|
static inline Optional create(const T* y) {
|
||||||
return y ? Optional(*y) : Optional();
|
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/Compiler.h"
|
||||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -41,7 +42,12 @@ template <typename PointerTy, unsigned IntBits, typename IntType=unsigned,
|
|||||||
typename PtrTraits = PointerLikeTypeTraits<PointerTy> >
|
typename PtrTraits = PointerLikeTypeTraits<PointerTy> >
|
||||||
class PointerIntPair {
|
class PointerIntPair {
|
||||||
intptr_t Value;
|
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 - The bits that come from the pointer.
|
||||||
PointerBitMask =
|
PointerBitMask =
|
||||||
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable)-1),
|
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable)-1),
|
||||||
@ -59,8 +65,6 @@ class PointerIntPair {
|
|||||||
public:
|
public:
|
||||||
PointerIntPair() : Value(0) {}
|
PointerIntPair() : Value(0) {}
|
||||||
PointerIntPair(PointerTy PtrVal, IntType IntVal) {
|
PointerIntPair(PointerTy PtrVal, IntType IntVal) {
|
||||||
assert(IntBits <= PtrTraits::NumLowBitsAvailable &&
|
|
||||||
"PointerIntPair formed with integer size too large for pointer");
|
|
||||||
setPointerAndInt(PtrVal, IntVal);
|
setPointerAndInt(PtrVal, IntVal);
|
||||||
}
|
}
|
||||||
explicit PointerIntPair(PointerTy PtrVal) {
|
explicit PointerIntPair(PointerTy PtrVal) {
|
||||||
@ -79,7 +83,7 @@ public:
|
|||||||
void setPointer(PointerTy PtrVal) {
|
void setPointer(PointerTy PtrVal) {
|
||||||
intptr_t PtrWord
|
intptr_t PtrWord
|
||||||
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
||||||
assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
|
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||||
"Pointer is not sufficiently aligned");
|
"Pointer is not sufficiently aligned");
|
||||||
// Preserve all low bits, just update the pointer.
|
// Preserve all low bits, just update the pointer.
|
||||||
Value = PtrWord | (Value & ~PointerBitMask);
|
Value = PtrWord | (Value & ~PointerBitMask);
|
||||||
@ -87,7 +91,7 @@ public:
|
|||||||
|
|
||||||
void setInt(IntType IntVal) {
|
void setInt(IntType IntVal) {
|
||||||
intptr_t IntWord = static_cast<intptr_t>(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.
|
// Preserve all bits other than the ones we are updating.
|
||||||
Value &= ~ShiftedIntMask; // Remove integer field.
|
Value &= ~ShiftedIntMask; // Remove integer field.
|
||||||
@ -97,7 +101,7 @@ public:
|
|||||||
void initWithPointer(PointerTy PtrVal) {
|
void initWithPointer(PointerTy PtrVal) {
|
||||||
intptr_t PtrWord
|
intptr_t PtrWord
|
||||||
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
||||||
assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
|
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||||
"Pointer is not sufficiently aligned");
|
"Pointer is not sufficiently aligned");
|
||||||
Value = PtrWord;
|
Value = PtrWord;
|
||||||
}
|
}
|
||||||
@ -105,10 +109,10 @@ public:
|
|||||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
|
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
|
||||||
intptr_t PtrWord
|
intptr_t PtrWord
|
||||||
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
= reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal));
|
||||||
assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 &&
|
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||||
"Pointer is not sufficiently aligned");
|
"Pointer is not sufficiently aligned");
|
||||||
intptr_t IntWord = static_cast<intptr_t>(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");
|
||||||
|
|
||||||
Value = PtrWord | (IntWord << IntShift);
|
Value = PtrWord | (IntWord << IntShift);
|
||||||
}
|
}
|
||||||
@ -158,13 +162,13 @@ struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType> > {
|
|||||||
typedef PointerIntPair<PointerTy, IntBits, IntType> Ty;
|
typedef PointerIntPair<PointerTy, IntBits, IntType> Ty;
|
||||||
static Ty getEmptyKey() {
|
static Ty getEmptyKey() {
|
||||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||||
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable;
|
||||||
return Ty(reinterpret_cast<PointerTy>(Val), IntType((1 << IntBits)-1));
|
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||||
}
|
}
|
||||||
static Ty getTombstoneKey() {
|
static Ty getTombstoneKey() {
|
||||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||||
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
||||||
return Ty(reinterpret_cast<PointerTy>(Val), IntType(0));
|
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||||
}
|
}
|
||||||
static unsigned getHashValue(Ty V) {
|
static unsigned getHashValue(Ty V) {
|
||||||
uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue());
|
uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue());
|
||||||
|
@ -15,8 +15,9 @@
|
|||||||
#ifndef LLVM_ADT_POINTERUNION_H
|
#ifndef LLVM_ADT_POINTERUNION_H
|
||||||
#define 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/ADT/PointerIntPair.h"
|
||||||
|
#include "llvm/Support/Compiler.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -153,6 +154,12 @@ namespace llvm {
|
|||||||
"Can't get the address because PointerLikeTypeTraits changes the ptr");
|
"Can't get the address because PointerLikeTypeTraits changes the ptr");
|
||||||
return (PT1 *)Val.getAddrOfPointer();
|
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
|
/// Assignment operators - Allow assigning into this union from either
|
||||||
/// pointer type, setting the discriminator to remember what it came from.
|
/// pointer type, setting the discriminator to remember what it came from.
|
||||||
@ -297,6 +304,12 @@ namespace llvm {
|
|||||||
if (is<T>()) return get<T>();
|
if (is<T>()) return get<T>();
|
||||||
return 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
|
/// Assignment operators - Allow assigning into this union from either
|
||||||
/// pointer type, setting the discriminator to remember what it came from.
|
/// pointer type, setting the discriminator to remember what it came from.
|
||||||
@ -406,6 +419,12 @@ namespace llvm {
|
|||||||
if (is<T>()) return get<T>();
|
if (is<T>()) return get<T>();
|
||||||
return 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
|
/// Assignment operators - Allow assigning into this union from either
|
||||||
/// pointer type, setting the discriminator to remember what it came from.
|
/// pointer type, setting the discriminator to remember what it came from.
|
||||||
@ -455,6 +474,33 @@ namespace llvm {
|
|||||||
::NumLowBitsAvailable
|
::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
|
#endif
|
||||||
|
@ -111,7 +111,7 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline po_iterator(NodeType *BB) {
|
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)));
|
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||||
traverseChild();
|
traverseChild();
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
|
|||||||
|
|
||||||
inline po_iterator(NodeType *BB, SetType &S) :
|
inline po_iterator(NodeType *BB, SetType &S) :
|
||||||
po_iterator_storage<SetType, ExtStorage>(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)));
|
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||||
traverseChild();
|
traverseChild();
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,18 @@
|
|||||||
// License. See LICENSE.TXT for details.
|
// License. See LICENSE.TXT for details.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
/// \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.
|
/// 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
|
||||||
// The SCC iterator has the important property that if a node in SCC S1 has an
|
/// algorithm.
|
||||||
// edge to a node in SCC S2, then it visits S1 *after* S2.
|
///
|
||||||
//
|
/// The SCC iterator has the important property that if a node in SCC S1 has an
|
||||||
// To visit S1 *before* S2, use the scc_iterator on the Inverse graph.
|
/// edge to a node in SCC S2, then it visits S1 *after* S2.
|
||||||
// (NOTE: This requires some simple wrappers and is not supported yet.)
|
///
|
||||||
//
|
/// 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
|
#ifndef LLVM_ADT_SCCITERATOR_H
|
||||||
@ -23,169 +25,112 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/GraphTraits.h"
|
#include "llvm/ADT/GraphTraits.h"
|
||||||
|
#include "llvm/ADT/iterator.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace llvm {
|
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
|
/// This is implemented using Tarjan's DFS algorithm using an internal stack to
|
||||||
/// reverse topological order of the SCC DAG.
|
/// 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> >
|
template <class GraphT, class GT = GraphTraits<GraphT>>
|
||||||
class scc_iterator
|
class scc_iterator
|
||||||
: public std::iterator<std::forward_iterator_tag,
|
: public iterator_facade_base<
|
||||||
std::vector<typename GT::NodeType>, ptrdiff_t> {
|
scc_iterator<GraphT, GT>, std::forward_iterator_tag,
|
||||||
typedef typename GT::NodeType NodeType;
|
const std::vector<typename GT::NodeType *>, ptrdiff_t> {
|
||||||
|
typedef typename GT::NodeType NodeType;
|
||||||
typedef typename GT::ChildIteratorType ChildItTy;
|
typedef typename GT::ChildIteratorType ChildItTy;
|
||||||
typedef std::vector<NodeType*> SccTy;
|
typedef std::vector<NodeType *> SccTy;
|
||||||
typedef std::iterator<std::forward_iterator_tag,
|
typedef typename scc_iterator::reference reference;
|
||||||
std::vector<typename GT::NodeType>, ptrdiff_t> super;
|
|
||||||
typedef typename super::reference reference;
|
|
||||||
typedef typename super::pointer pointer;
|
|
||||||
|
|
||||||
// The visit counters used to detect when a complete SCC is on the stack.
|
/// Element of VisitStack during DFS.
|
||||||
// visitNum is the global counter.
|
struct StackElement {
|
||||||
// nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
|
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;
|
unsigned visitNum;
|
||||||
DenseMap<NodeType *, unsigned> nodeVisitNumbers;
|
DenseMap<NodeType *, unsigned> nodeVisitNumbers;
|
||||||
|
|
||||||
// SCCNodeStack - Stack holding nodes of the SCC.
|
/// Stack holding nodes of the SCC.
|
||||||
std::vector<NodeType *> SCCNodeStack;
|
std::vector<NodeType *> SCCNodeStack;
|
||||||
|
|
||||||
// CurrentSCC - The current SCC, retrieved using operator*().
|
/// The current SCC, retrieved using operator*().
|
||||||
SccTy CurrentSCC;
|
SccTy CurrentSCC;
|
||||||
|
|
||||||
// VisitStack - Used to maintain the ordering. Top = current block
|
/// DFS stack, Used to maintain the ordering. The top contains the current
|
||||||
// First element is basic block pointer, second is the 'next child' to visit
|
/// node, the next child to visit, and the minimum uplink value of all child
|
||||||
std::vector<std::pair<NodeType *, ChildItTy> > VisitStack;
|
std::vector<StackElement> VisitStack;
|
||||||
|
|
||||||
// MinVisitNumStack - Stack holding the "min" values for each node in the DFS.
|
/// A single "visit" within the non-recursive DFS traversal.
|
||||||
// This is used to track the minimum uplink values for all children of
|
void DFSVisitOne(NodeType *N);
|
||||||
// the corresponding node on the VisitStack.
|
|
||||||
std::vector<unsigned> MinVisitNumStack;
|
|
||||||
|
|
||||||
// A single "visit" within the non-recursive DFS traversal.
|
/// The stack-based DFS traversal; defined below.
|
||||||
void DFSVisitOne(NodeType *N) {
|
void DFSVisitChildren();
|
||||||
++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.
|
/// Compute the next SCC using the DFS traversal.
|
||||||
void DFSVisitChildren() {
|
void GetNextSCC();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned childNum = nodeVisitNumbers[childN];
|
scc_iterator(NodeType *entryN) : visitNum(0) {
|
||||||
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) {
|
|
||||||
DFSVisitOne(entryN);
|
DFSVisitOne(entryN);
|
||||||
GetNextSCC();
|
GetNextSCC();
|
||||||
}
|
}
|
||||||
inline scc_iterator() { /* End is when DFS stack is empty */ }
|
|
||||||
|
/// End is when the DFS stack is empty.
|
||||||
|
scc_iterator() {}
|
||||||
|
|
||||||
public:
|
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"...
|
/// \brief Direct loop termination test which is more efficient than
|
||||||
static inline _Self begin(const GraphT &G){return _Self(GT::getEntryNode(G));}
|
/// comparison with \c end().
|
||||||
static inline _Self end (const GraphT &) { return _Self(); }
|
bool isAtEnd() const {
|
||||||
|
|
||||||
// Direct loop termination test: I.isAtEnd() is more efficient than I == end()
|
|
||||||
inline bool isAtEnd() const {
|
|
||||||
assert(!CurrentSCC.empty() || VisitStack.empty());
|
assert(!CurrentSCC.empty() || VisitStack.empty());
|
||||||
return CurrentSCC.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;
|
return VisitStack == x.VisitStack && CurrentSCC == x.CurrentSCC;
|
||||||
}
|
}
|
||||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
|
||||||
|
|
||||||
// Iterator traversal: forward iteration only
|
scc_iterator &operator++() {
|
||||||
inline _Self& operator++() { // Preincrement
|
|
||||||
GetNextSCC();
|
GetNextSCC();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
inline _Self operator++(int) { // Postincrement
|
|
||||||
_Self tmp = *this; ++*this; return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a reference to the current SCC
|
reference operator*() const {
|
||||||
inline const SccTy &operator*() const {
|
|
||||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
|
||||||
return CurrentSCC;
|
|
||||||
}
|
|
||||||
inline SccTy &operator*() {
|
|
||||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
||||||
return CurrentSCC;
|
return CurrentSCC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasLoop() -- Test if the current SCC has a loop. If it has more than one
|
/// \brief Test if the current SCC has a loop.
|
||||||
// node, this is trivially true. If not, it may still contain a loop if the
|
///
|
||||||
// node has an edge back to itself.
|
/// If the SCC has more than one node, this is trivially true. If not, it may
|
||||||
bool hasLoop() const {
|
/// still contain a loop if the node has an edge back to itself.
|
||||||
assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
|
bool hasLoop() const;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ReplaceNode - This informs the scc_iterator that the specified Old node
|
/// This informs the \c scc_iterator that the specified \c Old node
|
||||||
/// has been deleted, and New is to be used in its place.
|
/// has been deleted, and \c New is to be used in its place.
|
||||||
void ReplaceNode(NodeType *Old, NodeType *New) {
|
void ReplaceNode(NodeType *Old, NodeType *New) {
|
||||||
assert(nodeVisitNumbers.count(Old) && "Old not in scc_iterator?");
|
assert(nodeVisitNumbers.count(Old) && "Old not in scc_iterator?");
|
||||||
nodeVisitNumbers[New] = nodeVisitNumbers[Old];
|
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 GraphT, class GT>
|
||||||
template <class T>
|
void scc_iterator<GraphT, GT>::DFSVisitChildren() {
|
||||||
scc_iterator<T> scc_begin(const T &G) {
|
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);
|
return scc_iterator<T>::begin(G);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
/// \brief Construct the end iterator for a deduced graph type T.
|
||||||
scc_iterator<T> scc_end(const T &G) {
|
template <class T> scc_iterator<T> scc_end(const T &G) {
|
||||||
return scc_iterator<T>::end(G);
|
return scc_iterator<T>::end(G);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
/// \brief Construct the begin iterator for a deduced graph type T's Inverse<T>.
|
||||||
scc_iterator<Inverse<T> > scc_begin(const Inverse<T> &G) {
|
template <class T> scc_iterator<Inverse<T> > scc_begin(const Inverse<T> &G) {
|
||||||
return scc_iterator<Inverse<T> >::begin(G);
|
return scc_iterator<Inverse<T> >::begin(G);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
/// \brief Construct the end iterator for a deduced graph type T's Inverse<T>.
|
||||||
scc_iterator<Inverse<T> > scc_end(const Inverse<T> &G) {
|
template <class T> scc_iterator<Inverse<T> > scc_end(const Inverse<T> &G) {
|
||||||
return scc_iterator<Inverse<T> >::end(G);
|
return scc_iterator<Inverse<T> >::end(G);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,10 +17,12 @@
|
|||||||
#ifndef LLVM_ADT_STLEXTRAS_H
|
#ifndef LLVM_ADT_STLEXTRAS_H
|
||||||
#define LLVM_ADT_STLEXTRAS_H
|
#define LLVM_ADT_STLEXTRAS_H
|
||||||
|
|
||||||
|
#include "llvm/Support/Compiler.h"
|
||||||
#include <cstddef> // for std::size_t
|
#include <cstddef> // for std::size_t
|
||||||
#include <cstdlib> // for qsort
|
#include <cstdlib> // for qsort
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <utility> // for std::pair
|
#include <utility> // for std::pair
|
||||||
|
|
||||||
namespace llvm {
|
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
|
// deleter - Very very very simple method that is used to invoke operator
|
||||||
// delete on something. It is used like this:
|
// delete on something. It is used like this:
|
||||||
//
|
//
|
||||||
@ -95,8 +222,6 @@ public:
|
|||||||
|
|
||||||
inline explicit mapped_iterator(const RootIt &I, UnaryFunc F)
|
inline explicit mapped_iterator(const RootIt &I, UnaryFunc F)
|
||||||
: current(I), Fn(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
|
inline value_type operator*() const { // All this work to do this
|
||||||
return Fn(*current); // little change
|
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);
|
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>
|
// 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
|
/// \brief Function object to check whether the first component of a std::pair
|
||||||
/// compares less than the first component of another std::pair.
|
/// compares less than the first component of another std::pair.
|
||||||
struct less_first {
|
struct less_first {
|
||||||
@ -237,27 +290,20 @@ struct less_second {
|
|||||||
// Extra additions for arrays
|
// 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.
|
/// Find the length of an array.
|
||||||
template<class T, std::size_t N>
|
template <class T, std::size_t N>
|
||||||
inline size_t array_lengthof(T (&)[N]) {
|
LLVM_CONSTEXPR inline size_t array_lengthof(T (&)[N]) {
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// array_pod_sort_comparator - This is helper function for array_pod_sort,
|
/// Adapt std::less<T> for array_pod_sort.
|
||||||
/// which just uses operator< on T.
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline int array_pod_sort_comparator(const void *P1, const void *P2) {
|
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;
|
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 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -280,7 +326,7 @@ inline int (*get_array_pod_sort_comparator(const T &))
|
|||||||
/// possible.
|
/// possible.
|
||||||
///
|
///
|
||||||
/// This function assumes that you have simple POD-like types that can be
|
/// 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.
|
/// you should use std::sort.
|
||||||
///
|
///
|
||||||
/// NOTE: If qsort_r were portable, we could allow a custom comparator and
|
/// NOTE: If qsort_r were portable, we could allow a custom comparator and
|
||||||
@ -327,6 +373,170 @@ void DeleteContainerSeconds(Container &C) {
|
|||||||
C.clear();
|
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
|
} // End llvm namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -148,6 +148,7 @@ public:
|
|||||||
/// ScopeTy - This is a helpful typedef that allows clients to get easy access
|
/// ScopeTy - This is a helpful typedef that allows clients to get easy access
|
||||||
/// to the name of the scope for this hash table.
|
/// to the name of the scope for this hash table.
|
||||||
typedef ScopedHashTableScope<K, V, KInfo, AllocatorTy> ScopeTy;
|
typedef ScopedHashTableScope<K, V, KInfo, AllocatorTy> ScopeTy;
|
||||||
|
typedef unsigned size_type;
|
||||||
private:
|
private:
|
||||||
typedef ScopedHashTableVal<K, V> ValTy;
|
typedef ScopedHashTableVal<K, V> ValTy;
|
||||||
DenseMap<K, ValTy*, KInfo> TopLevelMap;
|
DenseMap<K, ValTy*, KInfo> TopLevelMap;
|
||||||
@ -159,20 +160,19 @@ private:
|
|||||||
void operator=(const ScopedHashTable&); // NOT YET IMPLEMENTED
|
void operator=(const ScopedHashTable&); // NOT YET IMPLEMENTED
|
||||||
friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
|
friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
|
||||||
public:
|
public:
|
||||||
ScopedHashTable() : CurScope(0) {}
|
ScopedHashTable() : CurScope(nullptr) {}
|
||||||
ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {}
|
ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {}
|
||||||
~ScopedHashTable() {
|
~ScopedHashTable() {
|
||||||
assert(CurScope == 0 && TopLevelMap.empty() && "Scope imbalance!");
|
assert(!CurScope && TopLevelMap.empty() && "Scope imbalance!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Access to the allocator.
|
/// Access to the allocator.
|
||||||
typedef typename ReferenceAdder<AllocatorTy>::result AllocatorRefTy;
|
AllocatorTy &getAllocator() { return Allocator; }
|
||||||
typedef typename ReferenceAdder<const AllocatorTy>::result AllocatorCRefTy;
|
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||||
AllocatorRefTy getAllocator() { return Allocator; }
|
|
||||||
AllocatorCRefTy 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);
|
return TopLevelMap.count(Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ ScopedHashTableScope<K, V, KInfo, Allocator>::
|
|||||||
ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) {
|
ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) {
|
||||||
PrevScope = HT.CurScope;
|
PrevScope = HT.CurScope;
|
||||||
HT.CurScope = this;
|
HT.CurScope = this;
|
||||||
LastValInScope = 0;
|
LastValInScope = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V, typename KInfo, typename Allocator>
|
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.
|
// Pop and delete all values corresponding to this scope.
|
||||||
while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) {
|
while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) {
|
||||||
// Pop this value out of the TopLevelMap.
|
// Pop this value out of the TopLevelMap.
|
||||||
if (ThisEntry->getNextForKey() == 0) {
|
if (!ThisEntry->getNextForKey()) {
|
||||||
assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry &&
|
assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry &&
|
||||||
"Scope imbalance!");
|
"Scope imbalance!");
|
||||||
HT.TopLevelMap.erase(ThisEntry->getKey());
|
HT.TopLevelMap.erase(ThisEntry->getKey());
|
||||||
|
@ -195,11 +195,10 @@ private:
|
|||||||
set_type &set_;
|
set_type &set_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename UnaryPredicate::argument_type argument_type;
|
|
||||||
|
|
||||||
TestAndEraseFromSet(UnaryPredicate P, set_type &set_) : P(P), set_(set_) {}
|
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)) {
|
if (P(Arg)) {
|
||||||
set_.erase(Arg);
|
set_.erase(Arg);
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,6 +54,7 @@ class SmallBitVector {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef unsigned size_type;
|
||||||
// Encapsulation of a single bit.
|
// Encapsulation of a single bit.
|
||||||
class reference {
|
class reference {
|
||||||
SmallBitVector &TheVector;
|
SmallBitVector &TheVector;
|
||||||
@ -153,11 +154,9 @@ public:
|
|||||||
switchToLarge(new BitVector(*RHS.getPointer()));
|
switchToLarge(new BitVector(*RHS.getPointer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
SmallBitVector(SmallBitVector &&RHS) : X(RHS.X) {
|
SmallBitVector(SmallBitVector &&RHS) : X(RHS.X) {
|
||||||
RHS.X = 1;
|
RHS.X = 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
~SmallBitVector() {
|
~SmallBitVector() {
|
||||||
if (!isSmall())
|
if (!isSmall())
|
||||||
@ -175,7 +174,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// count - Returns the number of bits which are set.
|
/// count - Returns the number of bits which are set.
|
||||||
unsigned count() const {
|
size_type count() const {
|
||||||
if (isSmall()) {
|
if (isSmall()) {
|
||||||
uintptr_t Bits = getSmallBits();
|
uintptr_t Bits = getSmallBits();
|
||||||
if (NumBaseBits == 32)
|
if (NumBaseBits == 32)
|
||||||
@ -506,7 +505,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
const SmallBitVector &operator=(SmallBitVector &&RHS) {
|
const SmallBitVector &operator=(SmallBitVector &&RHS) {
|
||||||
if (this != &RHS) {
|
if (this != &RHS) {
|
||||||
clear();
|
clear();
|
||||||
@ -514,7 +512,6 @@ public:
|
|||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void swap(SmallBitVector &RHS) {
|
void swap(SmallBitVector &RHS) {
|
||||||
std::swap(X, RHS.X);
|
std::swap(X, RHS.X);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// This file defines the SmallPtrSet class. See the doxygen comment for
|
// 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;
|
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
|
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||||
/// for small and one for large sets.
|
/// 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
|
/// (-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.
|
/// more. When this happens, the table is doubled in size.
|
||||||
///
|
///
|
||||||
class SmallPtrSetImpl {
|
class SmallPtrSetImplBase {
|
||||||
friend class SmallPtrSetIteratorImpl;
|
friend class SmallPtrSetIteratorImpl;
|
||||||
protected:
|
protected:
|
||||||
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
||||||
@ -60,19 +60,22 @@ protected:
|
|||||||
unsigned NumElements;
|
unsigned NumElements;
|
||||||
unsigned NumTombstones;
|
unsigned NumTombstones;
|
||||||
|
|
||||||
// Helper to copy construct a SmallPtrSet.
|
// Helpers to copy and move construct a SmallPtrSet.
|
||||||
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl& that);
|
SmallPtrSetImplBase(const void **SmallStorage, const SmallPtrSetImplBase &that);
|
||||||
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize) :
|
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||||
|
SmallPtrSetImplBase &&that);
|
||||||
|
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) :
|
||||||
SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) {
|
SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) {
|
||||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||||
"Initial size must be a power of two!");
|
"Initial size must be a power of two!");
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
~SmallPtrSetImpl();
|
~SmallPtrSetImplBase();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef unsigned size_type;
|
||||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
|
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
|
||||||
unsigned size() const { return NumElements; }
|
size_type size() const { return NumElements; }
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
// If the capacity of the array is huge, and the # elements used is small,
|
// 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.
|
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||||
void Grow(unsigned NewSize);
|
void Grow(unsigned NewSize);
|
||||||
|
|
||||||
void operator=(const SmallPtrSetImpl &RHS) LLVM_DELETED_FUNCTION;
|
void operator=(const SmallPtrSetImplBase &RHS) LLVM_DELETED_FUNCTION;
|
||||||
protected:
|
protected:
|
||||||
/// swap - Swaps the elements of two sets.
|
/// swap - Swaps the elements of two sets.
|
||||||
/// Note: This method assumes that both sets have the same small size.
|
/// 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
|
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||||
@ -163,8 +167,8 @@ protected:
|
|||||||
void AdvanceIfNotValid() {
|
void AdvanceIfNotValid() {
|
||||||
assert(Bucket <= End);
|
assert(Bucket <= End);
|
||||||
while (Bucket != End &&
|
while (Bucket != End &&
|
||||||
(*Bucket == SmallPtrSetImpl::getEmptyMarker() ||
|
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||||
*Bucket == SmallPtrSetImpl::getTombstoneMarker()))
|
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||||
++Bucket;
|
++Bucket;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -228,26 +232,25 @@ struct RoundUpToPowerOfTwo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
/// \brief A templated base class for \c SmallPtrSet which provides the
|
||||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
/// typesafe interface that is common across all small sizes.
|
||||||
/// power of two if it is not already a power of two. See the comments above
|
///
|
||||||
/// SmallPtrSetImpl for details of the algorithm.
|
/// This is particularly useful for passing around between interface boundaries
|
||||||
template<class PtrType, unsigned SmallSize>
|
/// to avoid encoding a particular small size in the interface boundary.
|
||||||
class SmallPtrSet : public SmallPtrSetImpl {
|
template <typename PtrType>
|
||||||
// Make sure that SmallSize is a power of two, round up if not.
|
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
|
||||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
|
||||||
const void *SmallStorage[SmallSizePowTwo];
|
|
||||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
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:
|
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
|
/// insert - This returns true if the pointer was new to the set, false if it
|
||||||
/// was already in the set.
|
/// was already in the set.
|
||||||
bool insert(PtrType Ptr) {
|
bool insert(PtrType Ptr) {
|
||||||
@ -260,9 +263,9 @@ public:
|
|||||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// count - Return true if the specified pointer is in the set.
|
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||||
bool count(PtrType Ptr) const {
|
size_type count(PtrType Ptr) const {
|
||||||
return count_imp(PtrTraits::getAsVoidPointer(Ptr));
|
return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IterT>
|
template <typename IterT>
|
||||||
@ -279,18 +282,48 @@ public:
|
|||||||
inline iterator end() const {
|
inline iterator end() const {
|
||||||
return iterator(CurArray+CurArraySize, CurArray+CurArraySize);
|
return iterator(CurArray+CurArraySize, CurArray+CurArraySize);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Allow assignment from any smallptrset with the same element type even if it
|
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||||
// doesn't have the same smallsize.
|
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||||
const SmallPtrSet<PtrType, SmallSize>&
|
/// 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) {
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// swap - Swaps the elements of two sets.
|
/// swap - Swaps the elements of two sets.
|
||||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
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>::const_iterator VIterator;
|
||||||
typedef typename SmallVector<T, N>::iterator mutable_iterator;
|
typedef typename SmallVector<T, N>::iterator mutable_iterator;
|
||||||
public:
|
public:
|
||||||
|
typedef size_t size_type;
|
||||||
SmallSet() {}
|
SmallSet() {}
|
||||||
|
|
||||||
bool empty() const { return Vector.empty() && Set.empty(); }
|
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||||
unsigned size() const {
|
return Vector.empty() && Set.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const {
|
||||||
return isSmall() ? Vector.size() : Set.size();
|
return isSmall() ? Vector.size() : Set.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// count - Return true if the element is in the set.
|
/// count - Return 1 if the element is in the set, 0 otherwise.
|
||||||
bool count(const T &V) const {
|
size_type count(const T &V) const {
|
||||||
if (isSmall()) {
|
if (isSmall()) {
|
||||||
// Since the collection is small, just do a linear search.
|
// Since the collection is small, just do a linear search.
|
||||||
return vfind(V) != Vector.end();
|
return vfind(V) == Vector.end() ? 0 : 1;
|
||||||
} else {
|
} else {
|
||||||
return Set.count(V);
|
return Set.count(V);
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,6 @@ public:
|
|||||||
template<typename ItTy>
|
template<typename ItTy>
|
||||||
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
|
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
|
// 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.
|
// duplicate the inherited versions so as not to inadvertently hide them.
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#ifndef LLVM_ADT_SMALLVECTOR_H
|
#ifndef LLVM_ADT_SMALLVECTOR_H
|
||||||
#define LLVM_ADT_SMALLVECTOR_H
|
#define LLVM_ADT_SMALLVECTOR_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/iterator_range.h"
|
||||||
#include "llvm/Support/AlignOf.h"
|
#include "llvm/Support/AlignOf.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
@ -183,13 +184,9 @@ protected:
|
|||||||
/// std::move, but not all stdlibs actually provide that.
|
/// std::move, but not all stdlibs actually provide that.
|
||||||
template<typename It1, typename It2>
|
template<typename It1, typename It2>
|
||||||
static It2 move(It1 I, It1 E, It2 Dest) {
|
static It2 move(It1 I, It1 E, It2 Dest) {
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
for (; I != E; ++I, ++Dest)
|
for (; I != E; ++I, ++Dest)
|
||||||
*Dest = ::std::move(*I);
|
*Dest = ::std::move(*I);
|
||||||
return Dest;
|
return Dest;
|
||||||
#else
|
|
||||||
return ::std::copy(I, E, Dest);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// move_backward - Use move-assignment to move the range
|
/// move_backward - Use move-assignment to move the range
|
||||||
@ -198,25 +195,17 @@ protected:
|
|||||||
/// std::move_backward, but not all stdlibs actually provide that.
|
/// std::move_backward, but not all stdlibs actually provide that.
|
||||||
template<typename It1, typename It2>
|
template<typename It1, typename It2>
|
||||||
static It2 move_backward(It1 I, It1 E, It2 Dest) {
|
static It2 move_backward(It1 I, It1 E, It2 Dest) {
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
while (I != E)
|
while (I != E)
|
||||||
*--Dest = ::std::move(*--E);
|
*--Dest = ::std::move(*--E);
|
||||||
return Dest;
|
return Dest;
|
||||||
#else
|
|
||||||
return ::std::copy_backward(I, E, Dest);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// uninitialized_move - Move the range [I, E) into the uninitialized
|
/// uninitialized_move - Move the range [I, E) into the uninitialized
|
||||||
/// memory starting with "Dest", constructing elements as needed.
|
/// memory starting with "Dest", constructing elements as needed.
|
||||||
template<typename It1, typename It2>
|
template<typename It1, typename It2>
|
||||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
for (; I != E; ++I, ++Dest)
|
for (; I != E; ++I, ++Dest)
|
||||||
::new ((void*) &*Dest) T(::std::move(*I));
|
::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
|
/// 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
|
/// Guarantees space for at least one more element, or MinSize more
|
||||||
/// elements if specified.
|
/// elements if specified.
|
||||||
void grow(size_t MinSize = 0);
|
void grow(size_t MinSize = 0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void push_back(const T &Elt) {
|
void push_back(const T &Elt) {
|
||||||
if (this->EndX < this->CapacityX) {
|
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||||
Retry:
|
this->grow();
|
||||||
::new ((void*) this->end()) T(Elt);
|
::new ((void*) this->end()) T(Elt);
|
||||||
this->setEnd(this->end()+1);
|
this->setEnd(this->end()+1);
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->grow();
|
|
||||||
goto Retry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
void push_back(T &&Elt) {
|
void push_back(T &&Elt) {
|
||||||
if (this->EndX < this->CapacityX) {
|
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||||
Retry:
|
this->grow();
|
||||||
::new ((void*) this->end()) T(::std::move(Elt));
|
::new ((void*) this->end()) T(::std::move(Elt));
|
||||||
this->setEnd(this->end()+1);
|
this->setEnd(this->end()+1);
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->grow();
|
|
||||||
goto Retry;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void pop_back() {
|
void pop_back() {
|
||||||
this->setEnd(this->end()-1);
|
this->setEnd(this->end()-1);
|
||||||
this->end()->~T();
|
this->end()->~T();
|
||||||
@ -268,7 +247,7 @@ template <typename T, bool isPodLike>
|
|||||||
void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
|
void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
|
||||||
size_t CurCapacity = this->capacity();
|
size_t CurCapacity = this->capacity();
|
||||||
size_t CurSize = this->size();
|
size_t CurSize = this->size();
|
||||||
// Always grow, even from zero.
|
// Always grow, even from zero.
|
||||||
size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
|
size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
|
||||||
if (NewCapacity < MinSize)
|
if (NewCapacity < MinSize)
|
||||||
NewCapacity = MinSize;
|
NewCapacity = MinSize;
|
||||||
@ -348,16 +327,12 @@ protected:
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
void push_back(const T &Elt) {
|
void push_back(const T &Elt) {
|
||||||
if (this->EndX < this->CapacityX) {
|
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||||
Retry:
|
this->grow();
|
||||||
memcpy(this->end(), &Elt, sizeof(T));
|
memcpy(this->end(), &Elt, sizeof(T));
|
||||||
this->setEnd(this->end()+1);
|
this->setEnd(this->end()+1);
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->grow();
|
|
||||||
goto Retry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_back() {
|
void pop_back() {
|
||||||
this->setEnd(this->end()-1);
|
this->setEnd(this->end()-1);
|
||||||
}
|
}
|
||||||
@ -405,7 +380,8 @@ public:
|
|||||||
} else if (N > this->size()) {
|
} else if (N > this->size()) {
|
||||||
if (this->capacity() < N)
|
if (this->capacity() < N)
|
||||||
this->grow(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);
|
this->setEnd(this->begin()+N);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,11 +404,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
|
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
T Result = ::std::move(this->back());
|
T Result = ::std::move(this->back());
|
||||||
#else
|
|
||||||
T Result = this->back();
|
|
||||||
#endif
|
|
||||||
this->pop_back();
|
this->pop_back();
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -501,7 +473,6 @@ public:
|
|||||||
return(N);
|
return(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
iterator insert(iterator I, T &&Elt) {
|
iterator insert(iterator I, T &&Elt) {
|
||||||
if (I == this->end()) { // Important special case for empty vector.
|
if (I == this->end()) { // Important special case for empty vector.
|
||||||
this->push_back(::std::move(Elt));
|
this->push_back(::std::move(Elt));
|
||||||
@ -511,28 +482,26 @@ public:
|
|||||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||||
|
|
||||||
if (this->EndX < this->CapacityX) {
|
if (this->EndX >= this->CapacityX) {
|
||||||
Retry:
|
size_t EltNo = I-this->begin();
|
||||||
::new ((void*) this->end()) T(::std::move(this->back()));
|
this->grow();
|
||||||
this->setEnd(this->end()+1);
|
I = this->begin()+EltNo;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
size_t EltNo = I-this->begin();
|
|
||||||
this->grow();
|
::new ((void*) this->end()) T(::std::move(this->back()));
|
||||||
I = this->begin()+EltNo;
|
// Push everything else over.
|
||||||
goto Retry;
|
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) {
|
iterator insert(iterator I, const T &Elt) {
|
||||||
if (I == this->end()) { // Important special case for empty vector.
|
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->begin() && "Insertion iterator is out of bounds.");
|
||||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||||
|
|
||||||
if (this->EndX < this->CapacityX) {
|
if (this->EndX >= this->CapacityX) {
|
||||||
Retry:
|
size_t EltNo = I-this->begin();
|
||||||
::new ((void*) this->end()) T(this->back());
|
this->grow();
|
||||||
this->setEnd(this->end()+1);
|
I = this->begin()+EltNo;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
size_t EltNo = I-this->begin();
|
::new ((void*) this->end()) T(std::move(this->back()));
|
||||||
this->grow();
|
// Push everything else over.
|
||||||
I = this->begin()+EltNo;
|
this->move_backward(I, this->end()-1, this->end());
|
||||||
goto Retry;
|
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) {
|
iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
|
||||||
@ -589,7 +556,8 @@ public:
|
|||||||
// reallocate the vector.
|
// reallocate the vector.
|
||||||
if (size_t(this->end()-I) >= NumToInsert) {
|
if (size_t(this->end()-I) >= NumToInsert) {
|
||||||
T *OldEnd = this->end();
|
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.
|
// Copy the existing elements that get replaced.
|
||||||
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||||
@ -642,7 +610,8 @@ public:
|
|||||||
// reallocate the vector.
|
// reallocate the vector.
|
||||||
if (size_t(this->end()-I) >= NumToInsert) {
|
if (size_t(this->end()-I) >= NumToInsert) {
|
||||||
T *OldEnd = this->end();
|
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.
|
// Copy the existing elements that get replaced.
|
||||||
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||||
@ -673,9 +642,7 @@ public:
|
|||||||
|
|
||||||
SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
|
SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
|
SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
|
||||||
#endif
|
|
||||||
|
|
||||||
bool operator==(const SmallVectorImpl &RHS) const {
|
bool operator==(const SmallVectorImpl &RHS) const {
|
||||||
if (this->size() != RHS.size()) return false;
|
if (this->size() != RHS.size()) return false;
|
||||||
@ -793,7 +760,6 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||||
// Avoid self-assignment.
|
// Avoid self-assignment.
|
||||||
@ -842,7 +808,7 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
|||||||
this->grow(RHSSize);
|
this->grow(RHSSize);
|
||||||
} else if (CurSize) {
|
} else if (CurSize) {
|
||||||
// Otherwise, use assignment for the already-constructed elements.
|
// 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.
|
// Move-construct the new elements in place.
|
||||||
@ -855,7 +821,6 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
|||||||
RHS.clear();
|
RHS.clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Storage for the SmallVector elements which aren't contained in
|
/// Storage for the SmallVector elements which aren't contained in
|
||||||
/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1'
|
/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1'
|
||||||
@ -894,6 +859,12 @@ public:
|
|||||||
this->append(S, E);
|
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) {
|
SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
|
||||||
if (!RHS.empty())
|
if (!RHS.empty())
|
||||||
SmallVectorImpl<T>::operator=(RHS);
|
SmallVectorImpl<T>::operator=(RHS);
|
||||||
@ -904,7 +875,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
|
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
|
||||||
if (!RHS.empty())
|
if (!RHS.empty())
|
||||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||||
@ -914,8 +884,6 @@ public:
|
|||||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, unsigned N>
|
template<typename T, unsigned N>
|
||||||
|
@ -45,6 +45,7 @@ struct SparseBitVectorElement
|
|||||||
: public ilist_node<SparseBitVectorElement<ElementSize> > {
|
: public ilist_node<SparseBitVectorElement<ElementSize> > {
|
||||||
public:
|
public:
|
||||||
typedef unsigned long BitWord;
|
typedef unsigned long BitWord;
|
||||||
|
typedef unsigned size_type;
|
||||||
enum {
|
enum {
|
||||||
BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT,
|
BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT,
|
||||||
BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE,
|
BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE,
|
||||||
@ -120,7 +121,7 @@ public:
|
|||||||
return Bits[Idx / BITWORD_SIZE] & (1L << (Idx % BITWORD_SIZE));
|
return Bits[Idx / BITWORD_SIZE] & (1L << (Idx % BITWORD_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned count() const {
|
size_type count() const {
|
||||||
unsigned NumBits = 0;
|
unsigned NumBits = 0;
|
||||||
for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i)
|
for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i)
|
||||||
if (sizeof(BitWord) == 4)
|
if (sizeof(BitWord) == 4)
|
||||||
@ -382,7 +383,7 @@ class SparseBitVector {
|
|||||||
AtEnd = true;
|
AtEnd = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Set up for next non zero word in bitmap.
|
// Set up for next non-zero word in bitmap.
|
||||||
BitNumber = Iter->index() * ElementSize;
|
BitNumber = Iter->index() * ElementSize;
|
||||||
NextSetBitNumber = Iter->find_first();
|
NextSetBitNumber = Iter->find_first();
|
||||||
BitNumber += NextSetBitNumber;
|
BitNumber += NextSetBitNumber;
|
||||||
|
@ -76,6 +76,10 @@ template<typename ValueT,
|
|||||||
typename KeyFunctorT = llvm::identity<unsigned>,
|
typename KeyFunctorT = llvm::identity<unsigned>,
|
||||||
typename SparseT = uint8_t>
|
typename SparseT = uint8_t>
|
||||||
class SparseMultiSet {
|
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
|
/// The actual data that's stored, as a doubly-linked list implemented via
|
||||||
/// indices into the DenseVector. The doubly linked list is implemented
|
/// indices into the DenseVector. The doubly linked list is implemented
|
||||||
/// circular in Prev indices, and INVALID-terminated in Next indices. This
|
/// circular in Prev indices, and INVALID-terminated in Next indices. This
|
||||||
@ -181,9 +185,10 @@ public:
|
|||||||
typedef const ValueT &const_reference;
|
typedef const ValueT &const_reference;
|
||||||
typedef ValueT *pointer;
|
typedef ValueT *pointer;
|
||||||
typedef const ValueT *const_pointer;
|
typedef const ValueT *const_pointer;
|
||||||
|
typedef unsigned size_type;
|
||||||
|
|
||||||
SparseMultiSet()
|
SparseMultiSet()
|
||||||
: Sparse(0), Universe(0), FreelistIdx(SMSNode::INVALID), NumFree(0) { }
|
: Sparse(nullptr), Universe(0), FreelistIdx(SMSNode::INVALID), NumFree(0) {}
|
||||||
|
|
||||||
~SparseMultiSet() { free(Sparse); }
|
~SparseMultiSet() { free(Sparse); }
|
||||||
|
|
||||||
@ -245,16 +250,6 @@ public:
|
|||||||
typedef typename super::pointer pointer;
|
typedef typename super::pointer pointer;
|
||||||
typedef typename super::reference reference;
|
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 {
|
reference operator*() const {
|
||||||
assert(isKeyed() && SMS->sparseIndex(SMS->Dense[Idx].Data) == SparseIdx &&
|
assert(isKeyed() && SMS->sparseIndex(SMS->Dense[Idx].Data) == SparseIdx &&
|
||||||
"Dereferencing iterator of invalid key or index");
|
"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
|
/// This is not the same as BitVector::size() which returns the size of the
|
||||||
/// universe.
|
/// universe.
|
||||||
///
|
///
|
||||||
unsigned size() const {
|
size_type size() const {
|
||||||
assert(NumFree <= Dense.size() && "Out-of-bounds free entries");
|
assert(NumFree <= Dense.size() && "Out-of-bounds free entries");
|
||||||
return Dense.size() - NumFree;
|
return Dense.size() - NumFree;
|
||||||
}
|
}
|
||||||
@ -354,9 +349,6 @@ public:
|
|||||||
///
|
///
|
||||||
iterator findIndex(unsigned Idx) {
|
iterator findIndex(unsigned Idx) {
|
||||||
assert(Idx < Universe && "Key out of range");
|
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;
|
const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
|
||||||
for (unsigned i = Sparse[Idx], e = Dense.size(); i < e; i += Stride) {
|
for (unsigned i = Sparse[Idx], e = Dense.size(); i < e; i += Stride) {
|
||||||
const unsigned FoundIdx = sparseIndex(Dense[i]);
|
const unsigned FoundIdx = sparseIndex(Dense[i]);
|
||||||
@ -387,7 +379,7 @@ public:
|
|||||||
|
|
||||||
/// Returns the number of elements identified by Key. This will be linear in
|
/// Returns the number of elements identified by Key. This will be linear in
|
||||||
/// the number of elements of that key.
|
/// the number of elements of that key.
|
||||||
unsigned count(const KeyT &Key) const {
|
size_type count(const KeyT &Key) const {
|
||||||
unsigned Ret = 0;
|
unsigned Ret = 0;
|
||||||
for (const_iterator It = find(Key); It != end(); ++It)
|
for (const_iterator It = find(Key); It != end(); ++It)
|
||||||
++Ret;
|
++Ret;
|
||||||
|
@ -118,8 +118,13 @@ template<typename ValueT,
|
|||||||
typename KeyFunctorT = llvm::identity<unsigned>,
|
typename KeyFunctorT = llvm::identity<unsigned>,
|
||||||
typename SparseT = uint8_t>
|
typename SparseT = uint8_t>
|
||||||
class SparseSet {
|
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 typename KeyFunctorT::argument_type KeyT;
|
||||||
typedef SmallVector<ValueT, 8> DenseT;
|
typedef SmallVector<ValueT, 8> DenseT;
|
||||||
|
typedef unsigned size_type;
|
||||||
DenseT Dense;
|
DenseT Dense;
|
||||||
SparseT *Sparse;
|
SparseT *Sparse;
|
||||||
unsigned Universe;
|
unsigned Universe;
|
||||||
@ -138,7 +143,7 @@ public:
|
|||||||
typedef ValueT *pointer;
|
typedef ValueT *pointer;
|
||||||
typedef const ValueT *const_pointer;
|
typedef const ValueT *const_pointer;
|
||||||
|
|
||||||
SparseSet() : Sparse(0), Universe(0) {}
|
SparseSet() : Sparse(nullptr), Universe(0) {}
|
||||||
~SparseSet() { free(Sparse); }
|
~SparseSet() { free(Sparse); }
|
||||||
|
|
||||||
/// setUniverse - Set the universe size which determines the largest key the
|
/// 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
|
/// This is not the same as BitVector::size() which returns the size of the
|
||||||
/// universe.
|
/// 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.
|
/// clear - Clears the set. This is a very fast constant time operation.
|
||||||
///
|
///
|
||||||
@ -198,9 +203,6 @@ public:
|
|||||||
///
|
///
|
||||||
iterator findIndex(unsigned Idx) {
|
iterator findIndex(unsigned Idx) {
|
||||||
assert(Idx < Universe && "Key out of range");
|
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;
|
const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
|
||||||
for (unsigned i = Sparse[Idx], e = size(); i < e; i += Stride) {
|
for (unsigned i = Sparse[Idx], e = size(); i < e; i += Stride) {
|
||||||
const unsigned FoundIdx = ValIndexOf(Dense[i]);
|
const unsigned FoundIdx = ValIndexOf(Dense[i]);
|
||||||
@ -227,10 +229,11 @@ public:
|
|||||||
return const_cast<SparseSet*>(this)->findIndex(KeyIndexOf(Key));
|
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 {
|
size_type count(const KeyT &Key) const {
|
||||||
return find(Key) != end();
|
return find(Key) == end() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// insert - Attempts to insert a new element.
|
/// insert - Attempts to insert a new element.
|
||||||
|
@ -46,7 +46,7 @@ public:
|
|||||||
/// construct - This should only be called for non-global statistics.
|
/// construct - This should only be called for non-global statistics.
|
||||||
void construct(const char *name, const char *desc) {
|
void construct(const char *name, const char *desc) {
|
||||||
Name = name; Desc = desc;
|
Name = name; Desc = desc;
|
||||||
Value = 0; Initialized = 0;
|
Value = 0; Initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow use of this class as the value itself.
|
// Allow use of this class as the value itself.
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
#ifndef LLVM_ADT_STRINGEXTRAS_H
|
#ifndef LLVM_ADT_STRINGEXTRAS_H
|
||||||
#define LLVM_ADT_STRINGEXTRAS_H
|
#define LLVM_ADT_STRINGEXTRAS_H
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
template<typename T> class SmallVectorImpl;
|
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;
|
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
|
/// Interpret the given character \p C as a hexadecimal digit and return its
|
||||||
/// value.
|
/// value.
|
||||||
///
|
///
|
||||||
@ -48,7 +53,7 @@ static inline unsigned hexDigitValue(char C) {
|
|||||||
/// This should only be used with unsigned types.
|
/// This should only be used with unsigned types.
|
||||||
///
|
///
|
||||||
template<typename IntTy>
|
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;
|
char *BufPtr = BufferEnd;
|
||||||
*--BufPtr = 0; // Null terminate buffer.
|
*--BufPtr = 0; // Null terminate buffer.
|
||||||
if (X == 0) {
|
if (X == 0) {
|
||||||
@ -58,15 +63,15 @@ static inline char *utohex_buffer(IntTy X, char *BufferEnd) {
|
|||||||
|
|
||||||
while (X) {
|
while (X) {
|
||||||
unsigned char Mod = static_cast<unsigned char>(X) & 15;
|
unsigned char Mod = static_cast<unsigned char>(X) & 15;
|
||||||
*--BufPtr = hexdigit(Mod);
|
*--BufPtr = hexdigit(Mod, LowerCase);
|
||||||
X >>= 4;
|
X >>= 4;
|
||||||
}
|
}
|
||||||
return BufPtr;
|
return BufPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::string utohexstr(uint64_t X) {
|
static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||||
char Buffer[17];
|
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) {
|
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
|
// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
|
||||||
// X*33+c -> X*33^c
|
// X*33+c -> X*33^c
|
||||||
static inline unsigned HashString(StringRef Str, unsigned Result = 0) {
|
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];
|
Result = Result * 33 + (unsigned char)Str[i];
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
template<typename ValueT>
|
template<typename ValueT>
|
||||||
@ -26,19 +27,6 @@ namespace llvm {
|
|||||||
template<typename ValueTy>
|
template<typename ValueTy>
|
||||||
class StringMapEntry;
|
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.
|
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||||
class StringMapEntryBase {
|
class StringMapEntryBase {
|
||||||
unsigned StrLen;
|
unsigned StrLen;
|
||||||
@ -61,15 +49,22 @@ protected:
|
|||||||
unsigned NumTombstones;
|
unsigned NumTombstones;
|
||||||
unsigned ItemSize;
|
unsigned ItemSize;
|
||||||
protected:
|
protected:
|
||||||
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {
|
explicit StringMapImpl(unsigned itemSize)
|
||||||
// Initialize the map with zero buckets to allocation.
|
: TheTable(nullptr),
|
||||||
TheTable = 0;
|
// Initialize the map with zero buckets to allocation.
|
||||||
NumBuckets = 0;
|
NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {}
|
||||||
NumItems = 0;
|
StringMapImpl(StringMapImpl &&RHS)
|
||||||
NumTombstones = 0;
|
: 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);
|
StringMapImpl(unsigned InitSize, unsigned ItemSize);
|
||||||
void RehashTable();
|
unsigned RehashTable(unsigned BucketNo = 0);
|
||||||
|
|
||||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
/// 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
|
/// 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)
|
explicit StringMapEntry(unsigned strLen)
|
||||||
: StringMapEntryBase(strLen), second() {}
|
: StringMapEntryBase(strLen), second() {}
|
||||||
StringMapEntry(unsigned strLen, const ValueTy &V)
|
StringMapEntry(unsigned strLen, ValueTy V)
|
||||||
: StringMapEntryBase(strLen), second(V) {}
|
: StringMapEntryBase(strLen), second(std::move(V)) {}
|
||||||
|
|
||||||
StringRef getKey() const {
|
StringRef getKey() const {
|
||||||
return StringRef(getKeyData(), getKeyLength());
|
return StringRef(getKeyData(), getKeyLength());
|
||||||
@ -144,15 +139,13 @@ public:
|
|||||||
/// Create - Create a StringMapEntry for the specified key and default
|
/// Create - Create a StringMapEntry for the specified key and default
|
||||||
/// construct the value.
|
/// construct the value.
|
||||||
template<typename AllocatorTy, typename InitType>
|
template<typename AllocatorTy, typename InitType>
|
||||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
|
static StringMapEntry *Create(StringRef Key,
|
||||||
AllocatorTy &Allocator,
|
AllocatorTy &Allocator,
|
||||||
InitType InitVal) {
|
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
|
// Allocate a new item with space for the string at the end and a null
|
||||||
// in. Allocate a new item with space for the string at the end and a null
|
|
||||||
// terminator.
|
// terminator.
|
||||||
|
|
||||||
unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
|
unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
|
||||||
KeyLength+1;
|
KeyLength+1;
|
||||||
unsigned Alignment = alignOf<StringMapEntry>();
|
unsigned Alignment = alignOf<StringMapEntry>();
|
||||||
@ -161,34 +154,29 @@ public:
|
|||||||
static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
|
static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
|
||||||
|
|
||||||
// Default construct the value.
|
// Default construct the value.
|
||||||
new (NewItem) StringMapEntry(KeyLength);
|
new (NewItem) StringMapEntry(KeyLength, std::move(InitVal));
|
||||||
|
|
||||||
// Copy the string information.
|
// Copy the string information.
|
||||||
char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
|
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.
|
StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
|
||||||
|
|
||||||
// Initialize the value if the client wants to.
|
|
||||||
StringMapEntryInitializer<ValueTy>::Initialize(*NewItem, InitVal);
|
|
||||||
return NewItem;
|
return NewItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename AllocatorTy>
|
template<typename AllocatorTy>
|
||||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
|
static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator) {
|
||||||
AllocatorTy &Allocator) {
|
return Create(Key, Allocator, ValueTy());
|
||||||
return Create(KeyStart, KeyEnd, Allocator, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create - Create a StringMapEntry with normal malloc/free.
|
/// Create - Create a StringMapEntry with normal malloc/free.
|
||||||
template<typename InitType>
|
template<typename InitType>
|
||||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
|
static StringMapEntry *Create(StringRef Key, InitType InitVal) {
|
||||||
InitType InitVal) {
|
|
||||||
MallocAllocator A;
|
MallocAllocator A;
|
||||||
return Create(KeyStart, KeyEnd, A, InitVal);
|
return Create(Key, A, std::move(InitVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd) {
|
static StringMapEntry *Create(StringRef Key) {
|
||||||
return Create(KeyStart, KeyEnd, ValueTy());
|
return Create(Key, ValueTy());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GetStringMapEntryFromValue - Given a value that is known to be embedded
|
/// GetStringMapEntryFromValue - Given a value that is known to be embedded
|
||||||
@ -216,8 +204,10 @@ public:
|
|||||||
template<typename AllocatorTy>
|
template<typename AllocatorTy>
|
||||||
void Destroy(AllocatorTy &Allocator) {
|
void Destroy(AllocatorTy &Allocator) {
|
||||||
// Free memory referenced by the item.
|
// Free memory referenced by the item.
|
||||||
|
unsigned AllocSize =
|
||||||
|
static_cast<unsigned>(sizeof(StringMapEntry)) + getKeyLength() + 1;
|
||||||
this->~StringMapEntry();
|
this->~StringMapEntry();
|
||||||
Allocator.Deallocate(this);
|
Allocator.Deallocate(static_cast<void *>(this), AllocSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroy this object, releasing memory back to the malloc allocator.
|
/// Destroy this object, releasing memory back to the malloc allocator.
|
||||||
@ -249,23 +239,19 @@ public:
|
|||||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||||
Allocator(A) {}
|
Allocator(A) {}
|
||||||
|
|
||||||
StringMap(const StringMap &RHS)
|
StringMap(StringMap &&RHS)
|
||||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
|
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
||||||
assert(RHS.empty() &&
|
|
||||||
"Copy ctor from non-empty stringmap not implemented yet!");
|
StringMap &operator=(StringMap RHS) {
|
||||||
(void)RHS;
|
StringMapImpl::swap(RHS);
|
||||||
}
|
std::swap(Allocator, RHS.Allocator);
|
||||||
void operator=(const StringMap &RHS) {
|
return *this;
|
||||||
assert(RHS.empty() &&
|
|
||||||
"assignment from non-empty stringmap not implemented yet!");
|
|
||||||
(void)RHS;
|
|
||||||
clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef typename ReferenceAdder<AllocatorTy>::result AllocatorRefTy;
|
// FIXME: Implement copy operations if/when they're needed.
|
||||||
typedef typename ReferenceAdder<const AllocatorTy>::result AllocatorCRefTy;
|
|
||||||
AllocatorRefTy getAllocator() { return Allocator; }
|
AllocatorTy &getAllocator() { return Allocator; }
|
||||||
AllocatorCRefTy getAllocator() const { return Allocator; }
|
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||||
|
|
||||||
typedef const char* key_type;
|
typedef const char* key_type;
|
||||||
typedef ValueTy mapped_type;
|
typedef ValueTy mapped_type;
|
||||||
@ -313,6 +299,7 @@ public:
|
|||||||
return GetOrCreateValue(Key).getValue();
|
return GetOrCreateValue(Key).getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||||
size_type count(StringRef Key) const {
|
size_type count(StringRef Key) const {
|
||||||
return find(Key) == end() ? 0 : 1;
|
return find(Key) == end() ? 0 : 1;
|
||||||
}
|
}
|
||||||
@ -336,6 +323,28 @@ public:
|
|||||||
return true;
|
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
|
// clear - Empties out the StringMap
|
||||||
void clear() {
|
void clear() {
|
||||||
if (empty()) return;
|
if (empty()) return;
|
||||||
@ -347,7 +356,7 @@ public:
|
|||||||
if (Bucket && Bucket != getTombstoneVal()) {
|
if (Bucket && Bucket != getTombstoneVal()) {
|
||||||
static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
|
static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
|
||||||
}
|
}
|
||||||
Bucket = 0;
|
Bucket = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumItems = 0;
|
NumItems = 0;
|
||||||
@ -359,25 +368,7 @@ public:
|
|||||||
/// return.
|
/// return.
|
||||||
template <typename InitTy>
|
template <typename InitTy>
|
||||||
MapEntryTy &GetOrCreateValue(StringRef Key, InitTy Val) {
|
MapEntryTy &GetOrCreateValue(StringRef Key, InitTy Val) {
|
||||||
unsigned BucketNo = LookupBucketFor(Key);
|
return *insert(std::make_pair(Key, std::move(Val))).first;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MapEntryTy &GetOrCreateValue(StringRef Key) {
|
MapEntryTy &GetOrCreateValue(StringRef Key) {
|
||||||
@ -404,7 +395,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~StringMap() {
|
~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);
|
free(TheTable);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -417,7 +418,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
typedef StringMapEntry<ValueTy> value_type;
|
typedef StringMapEntry<ValueTy> value_type;
|
||||||
|
|
||||||
StringMapConstIterator() : Ptr(0) { }
|
StringMapConstIterator() : Ptr(nullptr) { }
|
||||||
|
|
||||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||||
bool NoAdvance = false)
|
bool NoAdvance = false)
|
||||||
@ -450,7 +451,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void AdvancePastEmptyBuckets() {
|
void AdvancePastEmptyBuckets() {
|
||||||
while (*Ptr == 0 || *Ptr == StringMapImpl::getTombstoneVal())
|
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||||
++Ptr;
|
++Ptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#ifndef LLVM_ADT_STRINGREF_H
|
#ifndef LLVM_ADT_STRINGREF_H
|
||||||
#define LLVM_ADT_STRINGREF_H
|
#define LLVM_ADT_STRINGREF_H
|
||||||
|
|
||||||
#include "llvm/Support/type_traits.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -70,7 +69,7 @@ namespace llvm {
|
|||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Construct an empty string ref.
|
/// Construct an empty string ref.
|
||||||
/*implicit*/ StringRef() : Data(0), Length(0) {}
|
/*implicit*/ StringRef() : Data(nullptr), Length(0) {}
|
||||||
|
|
||||||
/// Construct a string ref from a cstring.
|
/// Construct a string ref from a cstring.
|
||||||
/*implicit*/ StringRef(const char *Str)
|
/*implicit*/ StringRef(const char *Str)
|
||||||
@ -124,6 +123,13 @@ namespace llvm {
|
|||||||
return Data[Length-1];
|
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
|
/// equals - Check for string equality, this is more efficient than
|
||||||
/// compare() when the relative ordering of inequal strings isn't needed.
|
/// compare() when the relative ordering of inequal strings isn't needed.
|
||||||
bool equals(StringRef RHS) const {
|
bool equals(StringRef RHS) const {
|
||||||
@ -179,7 +185,7 @@ namespace llvm {
|
|||||||
|
|
||||||
/// str - Get the contents as an std::string.
|
/// str - Get the contents as an std::string.
|
||||||
std::string str() const {
|
std::string str() const {
|
||||||
if (Data == 0) return std::string();
|
if (!Data) return std::string();
|
||||||
return std::string(Data, Length);
|
return std::string(Data, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +339,7 @@ namespace llvm {
|
|||||||
/// this returns true to signify the error. The string is considered
|
/// this returns true to signify the error. The string is considered
|
||||||
/// erroneous if empty or if it overflows T.
|
/// erroneous if empty or if it overflows T.
|
||||||
template <typename 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 {
|
getAsInteger(unsigned Radix, T &Result) const {
|
||||||
long long LLVal;
|
long long LLVal;
|
||||||
if (getAsSignedInteger(*this, Radix, LLVal) ||
|
if (getAsSignedInteger(*this, Radix, LLVal) ||
|
||||||
@ -344,7 +350,7 @@ namespace llvm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename 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 {
|
getAsInteger(unsigned Radix, T &Result) const {
|
||||||
unsigned long long ULLVal;
|
unsigned long long ULLVal;
|
||||||
if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
|
if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
|
||||||
@ -553,11 +559,6 @@ namespace llvm {
|
|||||||
// StringRefs can be treated like a POD type.
|
// StringRefs can be treated like a POD type.
|
||||||
template <typename T> struct isPodLike;
|
template <typename T> struct isPodLike;
|
||||||
template <> struct isPodLike<StringRef> { static const bool value = true; };
|
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
|
#endif
|
||||||
|
@ -49,7 +49,7 @@ class StringSwitch {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit StringSwitch(StringRef S)
|
explicit StringSwitch(StringRef S)
|
||||||
: Str(S), Result(0) { }
|
: Str(S), Result(nullptr) { }
|
||||||
|
|
||||||
template<unsigned N>
|
template<unsigned N>
|
||||||
StringSwitch& Case(const char (&S)[N], const T& Value) {
|
StringSwitch& Case(const char (&S)[N], const T& Value) {
|
||||||
|
@ -12,9 +12,7 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/PointerUnion.h"
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -70,9 +68,8 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLVM_HAS_RVALUE_REFERENCES
|
|
||||||
TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
|
TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
|
||||||
RHS.Val = (EltTy)0;
|
RHS.Val = (EltTy)nullptr;
|
||||||
}
|
}
|
||||||
TinyPtrVector &operator=(TinyPtrVector &&RHS) {
|
TinyPtrVector &operator=(TinyPtrVector &&RHS) {
|
||||||
if (this == &RHS)
|
if (this == &RHS)
|
||||||
@ -95,10 +92,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Val = RHS.Val;
|
Val = RHS.Val;
|
||||||
RHS.Val = (EltTy)0;
|
RHS.Val = (EltTy)nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// implicit conversion operator to ArrayRef.
|
// implicit conversion operator to ArrayRef.
|
||||||
operator ArrayRef<EltTy>() const {
|
operator ArrayRef<EltTy>() const {
|
||||||
@ -178,7 +174,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void push_back(EltTy NewVal) {
|
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 we have nothing, add something.
|
||||||
if (Val.isNull()) {
|
if (Val.isNull()) {
|
||||||
@ -199,7 +195,7 @@ public:
|
|||||||
void pop_back() {
|
void pop_back() {
|
||||||
// If we have a single value, convert to empty.
|
// If we have a single value, convert to empty.
|
||||||
if (Val.template is<EltTy>())
|
if (Val.template is<EltTy>())
|
||||||
Val = (EltTy)0;
|
Val = (EltTy)nullptr;
|
||||||
else if (VecTy *Vec = Val.template get<VecTy*>())
|
else if (VecTy *Vec = Val.template get<VecTy*>())
|
||||||
Vec->pop_back();
|
Vec->pop_back();
|
||||||
}
|
}
|
||||||
@ -207,7 +203,7 @@ public:
|
|||||||
void clear() {
|
void clear() {
|
||||||
// If we have a single value, convert to empty.
|
// If we have a single value, convert to empty.
|
||||||
if (Val.template is<EltTy>()) {
|
if (Val.template is<EltTy>()) {
|
||||||
Val = (EltTy)0;
|
Val = (EltTy)nullptr;
|
||||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||||
// If we have a vector form, just clear it.
|
// If we have a vector form, just clear it.
|
||||||
Vec->clear();
|
Vec->clear();
|
||||||
@ -222,7 +218,7 @@ public:
|
|||||||
// If we have a single value, convert to empty.
|
// If we have a single value, convert to empty.
|
||||||
if (Val.template is<EltTy>()) {
|
if (Val.template is<EltTy>()) {
|
||||||
if (I == begin())
|
if (I == begin())
|
||||||
Val = (EltTy)0;
|
Val = (EltTy)nullptr;
|
||||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||||
// multiple items in a vector; just do the erase, there is no
|
// multiple items in a vector; just do the erase, there is no
|
||||||
// benefit to collapsing back to a pointer
|
// benefit to collapsing back to a pointer
|
||||||
@ -238,7 +234,7 @@ public:
|
|||||||
|
|
||||||
if (Val.template is<EltTy>()) {
|
if (Val.template is<EltTy>()) {
|
||||||
if (S == begin() && S != E)
|
if (S == begin() && S != E)
|
||||||
Val = (EltTy)0;
|
Val = (EltTy)nullptr;
|
||||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||||
return Vec->erase(S, E);
|
return Vec->erase(S, E);
|
||||||
}
|
}
|
||||||
@ -250,7 +246,7 @@ public:
|
|||||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||||
if (I == end()) {
|
if (I == end()) {
|
||||||
push_back(Elt);
|
push_back(Elt);
|
||||||
return llvm::prior(end());
|
return std::prev(end());
|
||||||
}
|
}
|
||||||
assert(!Val.isNull() && "Null value with non-end insert iterator.");
|
assert(!Val.isNull() && "Null value with non-end insert iterator.");
|
||||||
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||||
@ -273,7 +269,7 @@ public:
|
|||||||
// If we have a single value, convert to a vector.
|
// If we have a single value, convert to a vector.
|
||||||
ptrdiff_t Offset = I - begin();
|
ptrdiff_t Offset = I - begin();
|
||||||
if (Val.isNull()) {
|
if (Val.isNull()) {
|
||||||
if (llvm::next(From) == To) {
|
if (std::next(From) == To) {
|
||||||
Val = *From;
|
Val = *From;
|
||||||
return begin();
|
return begin();
|
||||||
}
|
}
|
||||||
|
@ -46,32 +46,53 @@ public:
|
|||||||
enum ArchType {
|
enum ArchType {
|
||||||
UnknownArch,
|
UnknownArch,
|
||||||
|
|
||||||
arm, // ARM: arm, armv.*, xscale
|
arm, // ARM (little endian): arm, armv.*, xscale
|
||||||
aarch64, // AArch64: aarch64
|
armeb, // ARM (big endian): armeb
|
||||||
hexagon, // Hexagon: hexagon
|
arm64, // ARM64 (little endian): arm64
|
||||||
mips, // MIPS: mips, mipsallegrex
|
arm64_be, // ARM64 (big endian): arm64_be
|
||||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
aarch64, // AArch64 (little endian): aarch64
|
||||||
mips64, // MIPS64: mips64
|
aarch64_be, // AArch64 (big endian): aarch64_be
|
||||||
mips64el,// MIPS64EL: mips64el
|
hexagon, // Hexagon: hexagon
|
||||||
msp430, // MSP430: msp430
|
mips, // MIPS: mips, mipsallegrex
|
||||||
ppc, // PPC: powerpc
|
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||||
ppc64, // PPC64: powerpc64, ppu
|
mips64, // MIPS64: mips64
|
||||||
ppc64le, // PPC64LE: powerpc64le
|
mips64el, // MIPS64EL: mips64el
|
||||||
r600, // R600: AMD GPUs HD2XXX - HD6XXX
|
msp430, // MSP430: msp430
|
||||||
sparc, // Sparc: sparc
|
ppc, // PPC: powerpc
|
||||||
sparcv9, // Sparcv9: Sparcv9
|
ppc64, // PPC64: powerpc64, ppu
|
||||||
systemz, // SystemZ: s390x
|
ppc64le, // PPC64LE: powerpc64le
|
||||||
tce, // TCE (http://tce.cs.tut.fi/): tce
|
r600, // R600: AMD GPUs HD2XXX - HD6XXX
|
||||||
thumb, // Thumb: thumb, thumbv.*
|
sparc, // Sparc: sparc
|
||||||
x86, // X86: i[3-9]86
|
sparcv9, // Sparcv9: Sparcv9
|
||||||
x86_64, // X86-64: amd64, x86_64
|
systemz, // SystemZ: s390x
|
||||||
xcore, // XCore: xcore
|
tce, // TCE (http://tce.cs.tut.fi/): tce
|
||||||
nvptx, // NVPTX: 32-bit
|
thumb, // Thumb (little endian): thumb, thumbv.*
|
||||||
nvptx64, // NVPTX: 64-bit
|
thumbeb, // Thumb (big endian): thumbeb
|
||||||
le32, // le32: generic little-endian 32-bit CPU (PNaCl / Emscripten)
|
x86, // X86: i[3-9]86
|
||||||
amdil, // amdil: amd IL
|
x86_64, // X86-64: amd64, x86_64
|
||||||
spir, // SPIR: standard portable IR for OpenCL 32-bit version
|
xcore, // XCore: xcore
|
||||||
spir64 // SPIR: standard portable IR for OpenCL 64-bit version
|
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 {
|
enum VendorType {
|
||||||
UnknownVendor,
|
UnknownVendor,
|
||||||
@ -83,7 +104,10 @@ public:
|
|||||||
BGQ,
|
BGQ,
|
||||||
Freescale,
|
Freescale,
|
||||||
IBM,
|
IBM,
|
||||||
NVIDIA
|
ImaginationTechnologies,
|
||||||
|
MipsTechnologies,
|
||||||
|
NVIDIA,
|
||||||
|
CSR
|
||||||
};
|
};
|
||||||
enum OSType {
|
enum OSType {
|
||||||
UnknownOS,
|
UnknownOS,
|
||||||
@ -120,10 +144,21 @@ public:
|
|||||||
GNUEABI,
|
GNUEABI,
|
||||||
GNUEABIHF,
|
GNUEABIHF,
|
||||||
GNUX32,
|
GNUX32,
|
||||||
|
CODE16,
|
||||||
EABI,
|
EABI,
|
||||||
MachO,
|
EABIHF,
|
||||||
Android,
|
Android,
|
||||||
ELF
|
|
||||||
|
MSVC,
|
||||||
|
Itanium,
|
||||||
|
Cygnus,
|
||||||
|
};
|
||||||
|
enum ObjectFormatType {
|
||||||
|
UnknownObjectFormat,
|
||||||
|
|
||||||
|
COFF,
|
||||||
|
ELF,
|
||||||
|
MachO,
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -132,6 +167,9 @@ private:
|
|||||||
/// The parsed arch type.
|
/// The parsed arch type.
|
||||||
ArchType Arch;
|
ArchType Arch;
|
||||||
|
|
||||||
|
/// The parsed subarchitecture type.
|
||||||
|
SubArchType SubArch;
|
||||||
|
|
||||||
/// The parsed vendor type.
|
/// The parsed vendor type.
|
||||||
VendorType Vendor;
|
VendorType Vendor;
|
||||||
|
|
||||||
@ -141,13 +179,16 @@ private:
|
|||||||
/// The parsed Environment type.
|
/// The parsed Environment type.
|
||||||
EnvironmentType Environment;
|
EnvironmentType Environment;
|
||||||
|
|
||||||
|
/// The object format type.
|
||||||
|
ObjectFormatType ObjectFormat;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @name Constructors
|
/// @name Constructors
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// \brief Default constructor is the same as an empty string and leaves all
|
/// \brief Default constructor is the same as an empty string and leaves all
|
||||||
/// triple fields unknown.
|
/// triple fields unknown.
|
||||||
Triple() : Data(), Arch(), Vendor(), OS(), Environment() {}
|
Triple() : Data(), Arch(), Vendor(), OS(), Environment(), ObjectFormat() {}
|
||||||
|
|
||||||
explicit Triple(const Twine &Str);
|
explicit Triple(const Twine &Str);
|
||||||
Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr);
|
Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr);
|
||||||
@ -171,6 +212,9 @@ public:
|
|||||||
/// getArch - Get the parsed architecture type of this triple.
|
/// getArch - Get the parsed architecture type of this triple.
|
||||||
ArchType getArch() const { return Arch; }
|
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.
|
/// getVendor - Get the parsed vendor type of this triple.
|
||||||
VendorType getVendor() const { return Vendor; }
|
VendorType getVendor() const { return Vendor; }
|
||||||
|
|
||||||
@ -186,6 +230,9 @@ public:
|
|||||||
/// getEnvironment - Get the parsed environment type of this triple.
|
/// getEnvironment - Get the parsed environment type of this triple.
|
||||||
EnvironmentType getEnvironment() const { return Environment; }
|
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
|
/// getOSVersion - Parse the version number from the OS name component of the
|
||||||
/// triple, if present.
|
/// triple, if present.
|
||||||
///
|
///
|
||||||
@ -314,14 +361,42 @@ public:
|
|||||||
return isMacOSX() || isiOS();
|
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
|
/// \brief Tests for either Cygwin or MinGW OS
|
||||||
bool isOSCygMing() const {
|
bool isOSCygMing() const {
|
||||||
return getOS() == Triple::Cygwin || getOS() == Triple::MinGW32;
|
return isWindowsCygwinEnvironment() || isWindowsGNUEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Is this a "Windows" OS targeting a "MSVCRT.dll" environment.
|
/// \brief Is this a "Windows" OS targeting a "MSVCRT.dll" environment.
|
||||||
bool isOSMSVCRT() const {
|
bool isOSMSVCRT() const {
|
||||||
return getOS() == Triple::Win32 || getOS() == Triple::MinGW32;
|
return isWindowsMSVCEnvironment() || isWindowsGNUEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Tests whether the OS is Windows.
|
/// \brief Tests whether the OS is Windows.
|
||||||
@ -341,18 +416,17 @@ public:
|
|||||||
|
|
||||||
/// \brief Tests whether the OS uses the ELF binary format.
|
/// \brief Tests whether the OS uses the ELF binary format.
|
||||||
bool isOSBinFormatELF() const {
|
bool isOSBinFormatELF() const {
|
||||||
return !isOSDarwin() && !isOSWindows();
|
return getObjectFormat() == Triple::ELF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Tests whether the OS uses the COFF binary format.
|
/// \brief Tests whether the OS uses the COFF binary format.
|
||||||
bool isOSBinFormatCOFF() const {
|
bool isOSBinFormatCOFF() const {
|
||||||
return isOSWindows();
|
return getObjectFormat() == Triple::COFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Tests whether the environment is MachO.
|
/// \brief Tests whether the environment is MachO.
|
||||||
// FIXME: Should this be an OSBinFormat predicate?
|
bool isOSBinFormatMachO() const {
|
||||||
bool isEnvironmentMachO() const {
|
return getObjectFormat() == Triple::MachO;
|
||||||
return getEnvironment() == Triple::MachO || isOSDarwin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@ -375,6 +449,9 @@ public:
|
|||||||
/// to a known type.
|
/// to a known type.
|
||||||
void setEnvironment(EnvironmentType Kind);
|
void setEnvironment(EnvironmentType Kind);
|
||||||
|
|
||||||
|
/// setObjectFormat - Set the object file format
|
||||||
|
void setObjectFormat(ObjectFormatType Kind);
|
||||||
|
|
||||||
/// setTriple - Set all components to the new triple \p Str.
|
/// setTriple - Set all components to the new triple \p Str.
|
||||||
void setTriple(const Twine &Str);
|
void setTriple(const Twine &Str);
|
||||||
|
|
||||||
@ -422,6 +499,12 @@ public:
|
|||||||
/// architecture if no such variant can be found.
|
/// architecture if no such variant can be found.
|
||||||
llvm::Triple get64BitArchVariant() const;
|
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.
|
/// @name Static helpers for IDs.
|
||||||
/// @{
|
/// @{
|
||||||
|
@ -182,6 +182,10 @@ namespace llvm {
|
|||||||
assert(isValid() && "Invalid twine!");
|
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.
|
/// isNull - Check for the null twine.
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return getLHSKind() == NullKind;
|
return getLHSKind() == NullKind;
|
||||||
@ -374,7 +378,7 @@ namespace llvm {
|
|||||||
static Twine utohexstr(const uint64_t &Val) {
|
static Twine utohexstr(const uint64_t &Val) {
|
||||||
Child LHS, RHS;
|
Child LHS, RHS;
|
||||||
LHS.uHex = &Val;
|
LHS.uHex = &Val;
|
||||||
RHS.twine = 0;
|
RHS.twine = nullptr;
|
||||||
return Twine(LHS, UHexKind, RHS, EmptyKind);
|
return Twine(LHS, UHexKind, RHS, EmptyKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,13 +22,18 @@ namespace llvm {
|
|||||||
/// class should have an implementation of operator== and of operator<.
|
/// class should have an implementation of operator== and of operator<.
|
||||||
/// Entries can be fetched using operator[] with the entry ID.
|
/// Entries can be fetched using operator[] with the entry ID.
|
||||||
template<class T> class UniqueVector {
|
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:
|
private:
|
||||||
// Map - Used to handle the correspondence of entry to ID.
|
// Map - Used to handle the correspondence of entry to ID.
|
||||||
std::map<T, unsigned> Map;
|
std::map<T, unsigned> Map;
|
||||||
|
|
||||||
// Vector - ID ordered vector of entries. Entries can be indexed by ID - 1.
|
// Vector - ID ordered vector of entries. Entries can be indexed by ID - 1.
|
||||||
//
|
//
|
||||||
std::vector<T> Vector;
|
VectorType Vector;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// insert - Append entry to the vector if it doesn't already exist. Returns
|
/// insert - Append entry to the vector if it doesn't already exist. Returns
|
||||||
@ -68,6 +73,18 @@ public:
|
|||||||
return Vector[ID - 1];
|
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 - Returns the number of entries in the vector.
|
||||||
///
|
///
|
||||||
size_t size() const { return Vector.size(); }
|
size_t size() const { return Vector.size(); }
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
#define LLVM_ADT_EDIT_DISTANCE_H
|
#define LLVM_ADT_EDIT_DISTANCE_H
|
||||||
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ unsigned ComputeEditDistance(ArrayRef<T> FromArray, ArrayRef<T> ToArray,
|
|||||||
|
|
||||||
const unsigned SmallBufferSize = 64;
|
const unsigned SmallBufferSize = 64;
|
||||||
unsigned SmallBuffer[SmallBufferSize];
|
unsigned SmallBuffer[SmallBufferSize];
|
||||||
llvm::OwningArrayPtr<unsigned> Allocated;
|
std::unique_ptr<unsigned[]> Allocated;
|
||||||
unsigned *Previous = SmallBuffer;
|
unsigned *Previous = SmallBuffer;
|
||||||
if (2*(n + 1) > SmallBufferSize) {
|
if (2*(n + 1) > SmallBufferSize) {
|
||||||
Previous = new unsigned [2*(n+1)];
|
Previous = new unsigned [2*(n+1)];
|
||||||
|
@ -83,7 +83,7 @@ struct ilist_sentinel_traits {
|
|||||||
/// provideInitialHead - when constructing an ilist, provide a starting
|
/// provideInitialHead - when constructing an ilist, provide a starting
|
||||||
/// value for its Head
|
/// value for its Head
|
||||||
/// @return null node to indicate that it needs to be allocated later
|
/// @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
|
/// ensureHead - make sure that Head is either already
|
||||||
/// initialized or assigned a fresh sentinel
|
/// initialized or assigned a fresh sentinel
|
||||||
@ -92,7 +92,7 @@ struct ilist_sentinel_traits {
|
|||||||
if (!Head) {
|
if (!Head) {
|
||||||
Head = ilist_traits<NodeTy>::createSentinel();
|
Head = ilist_traits<NodeTy>::createSentinel();
|
||||||
ilist_traits<NodeTy>::noteHead(Head, Head);
|
ilist_traits<NodeTy>::noteHead(Head, Head);
|
||||||
ilist_traits<NodeTy>::setNext(Head, 0);
|
ilist_traits<NodeTy>::setNext(Head, nullptr);
|
||||||
return Head;
|
return Head;
|
||||||
}
|
}
|
||||||
return ilist_traits<NodeTy>::getPrev(Head);
|
return ilist_traits<NodeTy>::getPrev(Head);
|
||||||
@ -175,7 +175,7 @@ public:
|
|||||||
|
|
||||||
ilist_iterator(pointer NP) : NodePtr(NP) {}
|
ilist_iterator(pointer NP) : NodePtr(NP) {}
|
||||||
ilist_iterator(reference NR) : NodePtr(&NR) {}
|
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
|
// This is templated so that we can allow constructing a const iterator from
|
||||||
// a nonconst iterator...
|
// a nonconst iterator...
|
||||||
@ -383,7 +383,7 @@ public:
|
|||||||
// Miscellaneous inspection routines.
|
// Miscellaneous inspection routines.
|
||||||
size_type max_size() const { return size_type(-1); }
|
size_type max_size() const { return size_type(-1); }
|
||||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||||
return Head == 0 || Head == getTail();
|
return !Head || Head == getTail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Front and back accessor functions...
|
// Front and back accessor functions...
|
||||||
@ -451,8 +451,8 @@ public:
|
|||||||
// an ilist (and potentially deleted) with iterators still pointing at it.
|
// an ilist (and potentially deleted) with iterators still pointing at it.
|
||||||
// When those iterators are incremented or decremented, they will assert on
|
// When those iterators are incremented or decremented, they will assert on
|
||||||
// the null next/prev pointer instead of "usually working".
|
// the null next/prev pointer instead of "usually working".
|
||||||
this->setNext(Node, 0);
|
this->setNext(Node, nullptr);
|
||||||
this->setPrev(Node, 0);
|
this->setPrev(Node, nullptr);
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,9 +494,9 @@ private:
|
|||||||
// Note: we have to be careful about the case when we move the first node
|
// 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.
|
// in the list. This node is the list sentinel node and we can't move it.
|
||||||
NodeTy *ThisSentinel = getTail();
|
NodeTy *ThisSentinel = getTail();
|
||||||
setTail(0);
|
setTail(nullptr);
|
||||||
NodeTy *L2Sentinel = L2.getTail();
|
NodeTy *L2Sentinel = L2.getTail();
|
||||||
L2.setTail(0);
|
L2.setTail(nullptr);
|
||||||
|
|
||||||
// Remove [first, last) from its old position.
|
// Remove [first, last) from its old position.
|
||||||
NodeTy *First = &*first, *Prev = this->getPrev(First);
|
NodeTy *First = &*first, *Prev = this->getPrev(First);
|
||||||
@ -537,7 +537,7 @@ public:
|
|||||||
//
|
//
|
||||||
|
|
||||||
size_type LLVM_ATTRIBUTE_UNUSED_RESULT size() const {
|
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());
|
return std::distance(begin(), end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ protected:
|
|||||||
NodeTy *getPrev() { return Prev; }
|
NodeTy *getPrev() { return Prev; }
|
||||||
const NodeTy *getPrev() const { return Prev; }
|
const NodeTy *getPrev() const { return Prev; }
|
||||||
void setPrev(NodeTy *P) { Prev = P; }
|
void setPrev(NodeTy *P) { Prev = P; }
|
||||||
ilist_half_node() : Prev(0) {}
|
ilist_half_node() : Prev(nullptr) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename NodeTy>
|
template<typename NodeTy>
|
||||||
@ -48,7 +48,7 @@ class ilist_node : private ilist_half_node<NodeTy> {
|
|||||||
const NodeTy *getNext() const { return Next; }
|
const NodeTy *getNext() const { return Next; }
|
||||||
void setNext(NodeTy *N) { Next = N; }
|
void setNext(NodeTy *N) { Next = N; }
|
||||||
protected:
|
protected:
|
||||||
ilist_node() : Next(0) {}
|
ilist_node() : Next(nullptr) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @name Adjacent Node Accessors
|
/// @name Adjacent Node Accessors
|
||||||
@ -60,7 +60,7 @@ public:
|
|||||||
|
|
||||||
// Check for sentinel.
|
// Check for sentinel.
|
||||||
if (!Prev->getNext())
|
if (!Prev->getNext())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return Prev;
|
return Prev;
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ public:
|
|||||||
|
|
||||||
// Check for sentinel.
|
// Check for sentinel.
|
||||||
if (!Prev->getNext())
|
if (!Prev->getNext())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return Prev;
|
return Prev;
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ public:
|
|||||||
|
|
||||||
// Check for sentinel.
|
// Check for sentinel.
|
||||||
if (!Next->getNext())
|
if (!Next->getNext())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return Next;
|
return Next;
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ public:
|
|||||||
|
|
||||||
// Check for sentinel.
|
// Check for sentinel.
|
||||||
if (!Next->getNext())
|
if (!Next->getNext())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return Next;
|
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
|
#define LLVM_ANALYSIS_ALIASANALYSIS_H
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/Support/CallSite.h"
|
#include "llvm/IR/CallSite.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class DominatorTree;
|
|||||||
|
|
||||||
class AliasAnalysis {
|
class AliasAnalysis {
|
||||||
protected:
|
protected:
|
||||||
const DataLayout *TD;
|
const DataLayout *DL;
|
||||||
const TargetLibraryInfo *TLI;
|
const TargetLibraryInfo *TLI;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -75,7 +75,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Class identification, replacement for typeinfo
|
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
|
virtual ~AliasAnalysis(); // We want to be subclassed
|
||||||
|
|
||||||
/// UnknownSize - This is a special value which can be used with the
|
/// 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
|
/// getDataLayout - Return a pointer to the current DataLayout object, or
|
||||||
/// null if no DataLayout object is available.
|
/// 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
|
/// getTargetLibraryInfo - Return a pointer to the current TargetLibraryInfo
|
||||||
/// object, or null if no TargetLibraryInfo object is available.
|
/// 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.
|
/// the location, or null if there is no known unique tag.
|
||||||
const MDNode *TBAATag;
|
const MDNode *TBAATag;
|
||||||
|
|
||||||
explicit Location(const Value *P = 0, uint64_t S = UnknownSize,
|
explicit Location(const Value *P = nullptr, uint64_t S = UnknownSize,
|
||||||
const MDNode *N = 0)
|
const MDNode *N = nullptr)
|
||||||
: Ptr(P), Size(S), TBAATag(N) {}
|
: Ptr(P), Size(S), TBAATag(N) {}
|
||||||
|
|
||||||
Location getWithNewPtr(const Value *NewPtr) const {
|
Location getWithNewPtr(const Value *NewPtr) const {
|
||||||
@ -134,7 +134,7 @@ public:
|
|||||||
|
|
||||||
Location getWithoutTBAATag() const {
|
Location getWithoutTBAATag() const {
|
||||||
Location Copy(*this);
|
Location Copy(*this);
|
||||||
Copy.TBAATag = 0;
|
Copy.TBAATag = nullptr;
|
||||||
return Copy;
|
return Copy;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -274,6 +274,14 @@ public:
|
|||||||
UnknownModRefBehavior = Anywhere | ModRef
|
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.
|
/// getModRefBehavior - Return the behavior when calling the given call site.
|
||||||
virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||||
|
|
||||||
@ -560,12 +568,12 @@ struct DenseMapInfo<AliasAnalysis::Location> {
|
|||||||
static inline AliasAnalysis::Location getEmptyKey() {
|
static inline AliasAnalysis::Location getEmptyKey() {
|
||||||
return
|
return
|
||||||
AliasAnalysis::Location(DenseMapInfo<const Value *>::getEmptyKey(),
|
AliasAnalysis::Location(DenseMapInfo<const Value *>::getEmptyKey(),
|
||||||
0, 0);
|
0, nullptr);
|
||||||
}
|
}
|
||||||
static inline AliasAnalysis::Location getTombstoneKey() {
|
static inline AliasAnalysis::Location getTombstoneKey() {
|
||||||
return
|
return
|
||||||
AliasAnalysis::Location(DenseMapInfo<const Value *>::getTombstoneKey(),
|
AliasAnalysis::Location(DenseMapInfo<const Value *>::getTombstoneKey(),
|
||||||
0, 0);
|
0, nullptr);
|
||||||
}
|
}
|
||||||
static unsigned getHashValue(const AliasAnalysis::Location &Val) {
|
static unsigned getHashValue(const AliasAnalysis::Location &Val) {
|
||||||
return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^
|
return DenseMapInfo<const Value *>::getHashValue(Val.Ptr) ^
|
||||||
@ -597,6 +605,13 @@ bool isNoAliasArgument(const Value *V);
|
|||||||
///
|
///
|
||||||
bool isIdentifiedObject(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
|
} // End llvm namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/ilist.h"
|
#include "llvm/ADT/ilist.h"
|
||||||
#include "llvm/ADT/ilist_node.h"
|
#include "llvm/ADT/ilist_node.h"
|
||||||
#include "llvm/Support/ValueHandle.h"
|
#include "llvm/IR/ValueHandle.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -43,13 +43,13 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||||||
const MDNode *TBAAInfo;
|
const MDNode *TBAAInfo;
|
||||||
public:
|
public:
|
||||||
PointerRec(Value *V)
|
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()) {}
|
TBAAInfo(DenseMapInfo<const MDNode *>::getEmptyKey()) {}
|
||||||
|
|
||||||
Value *getValue() const { return Val; }
|
Value *getValue() const { return Val; }
|
||||||
|
|
||||||
PointerRec *getNext() const { return NextInList; }
|
PointerRec *getNext() const { return NextInList; }
|
||||||
bool hasAliasSet() const { return AS != 0; }
|
bool hasAliasSet() const { return AS != nullptr; }
|
||||||
|
|
||||||
PointerRec** setPrevInList(PointerRec **PIL) {
|
PointerRec** setPrevInList(PointerRec **PIL) {
|
||||||
PrevInList = PIL;
|
PrevInList = PIL;
|
||||||
@ -75,7 +75,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||||||
// If we have missing or conflicting TBAAInfo, return null.
|
// If we have missing or conflicting TBAAInfo, return null.
|
||||||
if (TBAAInfo == DenseMapInfo<const MDNode *>::getEmptyKey() ||
|
if (TBAAInfo == DenseMapInfo<const MDNode *>::getEmptyKey() ||
|
||||||
TBAAInfo == DenseMapInfo<const MDNode *>::getTombstoneKey())
|
TBAAInfo == DenseMapInfo<const MDNode *>::getTombstoneKey())
|
||||||
return 0;
|
return nullptr;
|
||||||
return TBAAInfo;
|
return TBAAInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setAliasSet(AliasSet *as) {
|
void setAliasSet(AliasSet *as) {
|
||||||
assert(AS == 0 && "Already have an alias set!");
|
assert(!AS && "Already have an alias set!");
|
||||||
AS = as;
|
AS = as;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
|||||||
*PrevInList = NextInList;
|
*PrevInList = NextInList;
|
||||||
if (AS->PtrListEnd == &NextInList) {
|
if (AS->PtrListEnd == &NextInList) {
|
||||||
AS->PtrListEnd = PrevInList;
|
AS->PtrListEnd = PrevInList;
|
||||||
assert(*AS->PtrListEnd == 0 && "List not terminated right!");
|
assert(*AS->PtrListEnd == nullptr && "List not terminated right!");
|
||||||
}
|
}
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ public:
|
|||||||
class iterator;
|
class iterator;
|
||||||
iterator begin() const { return iterator(PtrList); }
|
iterator begin() const { return iterator(PtrList); }
|
||||||
iterator end() const { return iterator(); }
|
iterator end() const { return iterator(); }
|
||||||
bool empty() const { return PtrList == 0; }
|
bool empty() const { return PtrList == nullptr; }
|
||||||
|
|
||||||
void print(raw_ostream &OS) const;
|
void print(raw_ostream &OS) const;
|
||||||
void dump() const;
|
void dump() const;
|
||||||
@ -184,7 +184,7 @@ public:
|
|||||||
PointerRec, ptrdiff_t> {
|
PointerRec, ptrdiff_t> {
|
||||||
PointerRec *CurNode;
|
PointerRec *CurNode;
|
||||||
public:
|
public:
|
||||||
explicit iterator(PointerRec *CN = 0) : CurNode(CN) {}
|
explicit iterator(PointerRec *CN = nullptr) : CurNode(CN) {}
|
||||||
|
|
||||||
bool operator==(const iterator& x) const {
|
bool operator==(const iterator& x) const {
|
||||||
return CurNode == x.CurNode;
|
return CurNode == x.CurNode;
|
||||||
@ -220,8 +220,9 @@ private:
|
|||||||
// Can only be created by AliasSetTracker. Also, ilist creates one
|
// Can only be created by AliasSetTracker. Also, ilist creates one
|
||||||
// to serve as a sentinel.
|
// to serve as a sentinel.
|
||||||
friend struct ilist_sentinel_traits<AliasSet>;
|
friend struct ilist_sentinel_traits<AliasSet>;
|
||||||
AliasSet() : PtrList(0), PtrListEnd(&PtrList), Forward(0), RefCount(0),
|
AliasSet()
|
||||||
AccessTy(NoModRef), AliasTy(MustAlias), Volatile(false) {
|
: PtrList(nullptr), PtrListEnd(&PtrList), Forward(nullptr), RefCount(0),
|
||||||
|
AccessTy(NoModRef), AliasTy(MustAlias), Volatile(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AliasSet(const AliasSet &AS) LLVM_DELETED_FUNCTION;
|
AliasSet(const AliasSet &AS) LLVM_DELETED_FUNCTION;
|
||||||
@ -282,10 +283,10 @@ class AliasSetTracker {
|
|||||||
/// notified whenever a Value is deleted.
|
/// notified whenever a Value is deleted.
|
||||||
class ASTCallbackVH : public CallbackVH {
|
class ASTCallbackVH : public CallbackVH {
|
||||||
AliasSetTracker *AST;
|
AliasSetTracker *AST;
|
||||||
virtual void deleted();
|
void deleted() override;
|
||||||
virtual void allUsesReplacedWith(Value *);
|
void allUsesReplacedWith(Value *) override;
|
||||||
public:
|
public:
|
||||||
ASTCallbackVH(Value *V, AliasSetTracker *AST = 0);
|
ASTCallbackVH(Value *V, AliasSetTracker *AST = nullptr);
|
||||||
ASTCallbackVH &operator=(Value *V);
|
ASTCallbackVH &operator=(Value *V);
|
||||||
};
|
};
|
||||||
/// ASTCallbackVHDenseMapInfo - Traits to tell DenseMap that tell us how to
|
/// ASTCallbackVHDenseMapInfo - Traits to tell DenseMap that tell us how to
|
||||||
@ -354,7 +355,7 @@ public:
|
|||||||
/// pointer didn't alias anything).
|
/// pointer didn't alias anything).
|
||||||
AliasSet &getAliasSetForPointer(Value *P, uint64_t Size,
|
AliasSet &getAliasSetForPointer(Value *P, uint64_t Size,
|
||||||
const MDNode *TBAAInfo,
|
const MDNode *TBAAInfo,
|
||||||
bool *New = 0);
|
bool *New = nullptr);
|
||||||
|
|
||||||
/// getAliasSetForPointerIfExists - Return the alias set containing the
|
/// getAliasSetForPointerIfExists - Return the alias set containing the
|
||||||
/// location specified if one exists, otherwise return null.
|
/// location specified if one exists, otherwise return null.
|
||||||
@ -408,7 +409,7 @@ private:
|
|||||||
// entry for the pointer if it doesn't already exist.
|
// entry for the pointer if it doesn't already exist.
|
||||||
AliasSet::PointerRec &getEntryFor(Value *V) {
|
AliasSet::PointerRec &getEntryFor(Value *V) {
|
||||||
AliasSet::PointerRec *&Entry = PointerMap[ASTCallbackVH(V, this)];
|
AliasSet::PointerRec *&Entry = PointerMap[ASTCallbackVH(V, this)];
|
||||||
if (Entry == 0)
|
if (!Entry)
|
||||||
Entry = new AliasSet::PointerRec(V);
|
Entry = new AliasSet::PointerRec(V);
|
||||||
return *Entry;
|
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
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -21,14 +21,13 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
class BranchProbabilityInfo;
|
class BranchProbabilityInfo;
|
||||||
template<class BlockT, class FunctionT, class BranchProbInfoT>
|
template <class BlockT> class BlockFrequencyInfoImpl;
|
||||||
class BlockFrequencyImpl;
|
|
||||||
|
|
||||||
/// BlockFrequencyInfo pass uses BlockFrequencyImpl implementation to estimate
|
/// BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to
|
||||||
/// IR basic block frequencies.
|
/// estimate IR basic block frequencies.
|
||||||
class BlockFrequencyInfo : public FunctionPass {
|
class BlockFrequencyInfo : public FunctionPass {
|
||||||
|
typedef BlockFrequencyInfoImpl<BasicBlock> ImplType;
|
||||||
BlockFrequencyImpl<BasicBlock, Function, BranchProbabilityInfo> *BFI;
|
std::unique_ptr<ImplType> BFI;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
@ -37,10 +36,11 @@ public:
|
|||||||
|
|
||||||
~BlockFrequencyInfo();
|
~BlockFrequencyInfo();
|
||||||
|
|
||||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||||
|
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F) override;
|
||||||
void print(raw_ostream &O, const Module *M) const;
|
void releaseMemory() override;
|
||||||
|
void print(raw_ostream &O, const Module *M) const override;
|
||||||
const Function *getFunction() const;
|
const Function *getFunction() const;
|
||||||
void view() const;
|
void view() const;
|
||||||
|
|
||||||
@ -50,6 +50,17 @@ public:
|
|||||||
/// comparison to the other block frequencies. We do this to avoid using of
|
/// comparison to the other block frequencies. We do this to avoid using of
|
||||||
/// floating points.
|
/// floating points.
|
||||||
BlockFrequency getBlockFreq(const BasicBlock *BB) const;
|
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/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
#include "llvm/IR/CFG.h"
|
||||||
#include "llvm/InitializePasses.h"
|
#include "llvm/InitializePasses.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Support/BranchProbability.h"
|
#include "llvm/Support/BranchProbability.h"
|
||||||
@ -44,9 +45,9 @@ public:
|
|||||||
initializeBranchProbabilityInfoPass(*PassRegistry::getPassRegistry());
|
initializeBranchProbabilityInfoPass(*PassRegistry::getPassRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F) override;
|
||||||
void print(raw_ostream &OS, const Module *M = 0) const;
|
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.
|
/// \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.
|
/// 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, 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.
|
/// \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
|
/// This allows a pass to explicitly set the edge weight for an edge. It can
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#define LLVM_ANALYSIS_CFG_H
|
#define LLVM_ANALYSIS_CFG_H
|
||||||
|
|
||||||
#include "llvm/IR/BasicBlock.h"
|
#include "llvm/IR/BasicBlock.h"
|
||||||
#include "llvm/Support/CFG.h"
|
#include "llvm/IR/CFG.h"
|
||||||
|
|
||||||
namespace llvm {
|
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
|
/// on branchy code but not loops, and LI is most useful on code with loops but
|
||||||
/// does not help on branchy code outside loops.
|
/// does not help on branchy code outside loops.
|
||||||
bool isPotentiallyReachable(const Instruction *From, const Instruction *To,
|
bool isPotentiallyReachable(const Instruction *From, const Instruction *To,
|
||||||
const DominatorTree *DT = 0,
|
const DominatorTree *DT = nullptr,
|
||||||
const LoopInfo *LI = 0);
|
const LoopInfo *LI = nullptr);
|
||||||
|
|
||||||
/// \brief Determine whether block 'To' is reachable from 'From', returning
|
/// \brief Determine whether block 'To' is reachable from 'From', returning
|
||||||
/// true if uncertain.
|
/// 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
|
/// Returns false only if we can prove that once 'From' has been reached then
|
||||||
/// 'To' can not be executed. Conservatively returns true.
|
/// 'To' can not be executed. Conservatively returns true.
|
||||||
bool isPotentiallyReachable(const BasicBlock *From, const BasicBlock *To,
|
bool isPotentiallyReachable(const BasicBlock *From, const BasicBlock *To,
|
||||||
const DominatorTree *DT = 0,
|
const DominatorTree *DT = nullptr,
|
||||||
const LoopInfo *LI = 0);
|
const LoopInfo *LI = nullptr);
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
||||||
|
@ -15,11 +15,10 @@
|
|||||||
#ifndef LLVM_ANALYSIS_CFGPRINTER_H
|
#ifndef LLVM_ANALYSIS_CFGPRINTER_H
|
||||||
#define 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/Constants.h"
|
||||||
#include "llvm/IR/Function.h"
|
#include "llvm/IR/Function.h"
|
||||||
#include "llvm/IR/Instructions.h"
|
#include "llvm/IR/Instructions.h"
|
||||||
#include "llvm/Support/CFG.h"
|
|
||||||
#include "llvm/Support/GraphWriter.h"
|
#include "llvm/Support/GraphWriter.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -40,7 +39,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
|||||||
std::string Str;
|
std::string Str;
|
||||||
raw_string_ostream OS(Str);
|
raw_string_ostream OS(Str);
|
||||||
|
|
||||||
WriteAsOperand(OS, Node, false);
|
Node->printAsOperand(OS, false);
|
||||||
return OS.str();
|
return OS.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
|||||||
raw_string_ostream OS(Str);
|
raw_string_ostream OS(Str);
|
||||||
|
|
||||||
if (Node->getName().empty()) {
|
if (Node->getName().empty()) {
|
||||||
WriteAsOperand(OS, Node, false);
|
Node->printAsOperand(OS, false);
|
||||||
OS << ":";
|
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.
|
// License. See LICENSE.TXT for details.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
/// \file
|
||||||
// This interface is used to build and manipulate a call graph, which is a very
|
///
|
||||||
// useful tool for interprocedural optimization.
|
/// 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 the are called by the function
|
/// Every function in a module is represented as a node in the call graph. The
|
||||||
// corresponding to the node.
|
/// 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
|
/// A call graph may contain nodes where the function that they correspond to
|
||||||
// represented (or analyzable) in the module. In particular, this analysis
|
/// is null. These 'external' nodes are used to represent control flow that is
|
||||||
// builds one external node such that:
|
/// not represented (or analyzable) in the module. In particular, this
|
||||||
// 1. All functions in the module without internal linkage will have edges
|
/// analysis builds one external node such that:
|
||||||
// from this external node, indicating that they could be called by
|
/// 1. All functions in the module without internal linkage will have edges
|
||||||
// functions outside of the module.
|
/// from this external node, indicating that they could be called by
|
||||||
// 2. All functions whose address is used for something more than a direct
|
/// functions outside of the module.
|
||||||
// call, for example being stored into a memory location will also have an
|
/// 2. All functions whose address is used for something more than a direct
|
||||||
// edge from this external node. Since they may be called by an unknown
|
/// call, for example being stored into a memory location will also have
|
||||||
// caller later, they must be tracked as such.
|
/// 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:
|
/// There is a second external node added for calls that leave this module.
|
||||||
// 1. The function is external, reflecting the fact that they could call
|
/// Functions have a call edge to the external node iff:
|
||||||
// anything without internal linkage or that has its address taken.
|
/// 1. The function is external, reflecting the fact that they could call
|
||||||
// 2. The function contains an indirect function 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)
|
/// As an extension in the future, there may be multiple nodes with a null
|
||||||
// that an indirect call site can call only a specific set of functions.
|
/// 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
|
/// Because of these properties, the CallGraph captures a conservative superset
|
||||||
// transformations.
|
/// 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'.
|
/// The CallGraph class also attempts to figure out what the root of the
|
||||||
// If no function named 'main' is found, the external node is used as the entry
|
/// CallGraph is, which it currently does by looking for a function named
|
||||||
// node, reflecting the fact that any function without internal linkage could
|
/// 'main'. If no function named 'main' is found, the external node is used as
|
||||||
// be called into (which is common for libraries).
|
/// 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
|
#ifndef LLVM_ANALYSIS_CALLGRAPH_H
|
||||||
@ -53,11 +54,11 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/GraphTraits.h"
|
#include "llvm/ADT/GraphTraits.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
|
#include "llvm/IR/CallSite.h"
|
||||||
#include "llvm/IR/Function.h"
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/ValueHandle.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Support/CallSite.h"
|
|
||||||
#include "llvm/Support/IncludeFile.h"
|
#include "llvm/Support/IncludeFile.h"
|
||||||
#include "llvm/Support/ValueHandle.h"
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -66,171 +67,142 @@ class Function;
|
|||||||
class Module;
|
class Module;
|
||||||
class CallGraphNode;
|
class CallGraphNode;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
/// \brief The basic data container for the call graph of a \c Module of IR.
|
||||||
// CallGraph class definition
|
///
|
||||||
//
|
/// This class exposes both the interface to the call graph for a module of IR.
|
||||||
class CallGraph : public ModulePass {
|
///
|
||||||
Module *Mod; // The module this call graph represents
|
/// 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;
|
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
|
/// \brief A map from \c Function* to \c CallGraphNode*.
|
||||||
// couldn't be found.
|
FunctionMapTy FunctionMap;
|
||||||
//
|
|
||||||
|
/// \brief Root is root of the call graph, or the external node if a 'main'
|
||||||
|
/// function couldn't be found.
|
||||||
CallGraphNode *Root;
|
CallGraphNode *Root;
|
||||||
|
|
||||||
// ExternalCallingNode - This node has edges to all external functions and
|
/// \brief This node has edges to all external functions and those internal
|
||||||
// those internal functions that have their address taken.
|
/// functions that have their address taken.
|
||||||
CallGraphNode *ExternalCallingNode;
|
CallGraphNode *ExternalCallingNode;
|
||||||
|
|
||||||
// CallsExternalNode - This node has edges to it from all functions making
|
/// \brief This node has edges to it from all functions making indirect calls
|
||||||
// indirect calls or calling an external function.
|
/// or calling an external function.
|
||||||
CallGraphNode *CallsExternalNode;
|
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
|
/// 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
|
/// splicing the body of one function to another while also updating all
|
||||||
/// callers from the old function to the new.
|
/// callers from the old function to the new.
|
||||||
///
|
|
||||||
void spliceFunction(const Function *From, const Function *To);
|
void spliceFunction(const Function *From, const Function *To);
|
||||||
|
|
||||||
// Add a function to the call graph, and link the node to all of the functions
|
/// \brief Add a function to the call graph, and link the node to all of the
|
||||||
// that it calls.
|
/// functions that it calls.
|
||||||
void addToCallGraph(Function *F);
|
void addToCallGraph(Function *F);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Class identification, replacement for typeinfo
|
CallGraph(Module &M);
|
||||||
//===---------------------------------------------------------------------
|
~CallGraph();
|
||||||
// Accessors.
|
|
||||||
//
|
void print(raw_ostream &OS) const;
|
||||||
|
void dump() const;
|
||||||
|
|
||||||
typedef FunctionMapTy::iterator iterator;
|
typedef FunctionMapTy::iterator iterator;
|
||||||
typedef FunctionMapTy::const_iterator const_iterator;
|
typedef FunctionMapTy::const_iterator const_iterator;
|
||||||
|
|
||||||
/// getModule - Return the module the call graph corresponds to.
|
/// \brief Returns the module the call graph corresponds to.
|
||||||
///
|
Module &getModule() const { return M; }
|
||||||
Module &getModule() const { return *Mod; }
|
|
||||||
|
|
||||||
inline iterator begin() { return FunctionMap.begin(); }
|
inline iterator begin() { return FunctionMap.begin(); }
|
||||||
inline iterator end() { return FunctionMap.end(); }
|
inline iterator end() { return FunctionMap.end(); }
|
||||||
inline const_iterator begin() const { return FunctionMap.begin(); }
|
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
|
/// \brief Returns the call graph node for the provided function.
|
||||||
// function
|
|
||||||
inline const CallGraphNode *operator[](const Function *F) const {
|
inline const CallGraphNode *operator[](const Function *F) const {
|
||||||
const_iterator I = FunctionMap.find(F);
|
const_iterator I = FunctionMap.find(F);
|
||||||
assert(I != FunctionMap.end() && "Function not in callgraph!");
|
assert(I != FunctionMap.end() && "Function not in callgraph!");
|
||||||
return I->second;
|
return I->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Returns the call graph node for the provided function.
|
||||||
inline CallGraphNode *operator[](const Function *F) {
|
inline CallGraphNode *operator[](const Function *F) {
|
||||||
const_iterator I = FunctionMap.find(F);
|
const_iterator I = FunctionMap.find(F);
|
||||||
assert(I != FunctionMap.end() && "Function not in callgraph!");
|
assert(I != FunctionMap.end() && "Function not in callgraph!");
|
||||||
return I->second;
|
return I->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the CallGraphNode which is used to represent undetermined calls
|
/// \brief Returns the \c CallGraphNode which is used to represent
|
||||||
/// into the callgraph.
|
/// undetermined calls into the callgraph.
|
||||||
CallGraphNode *getExternalCallingNode() const { return ExternalCallingNode; }
|
CallGraphNode *getExternalCallingNode() const { return ExternalCallingNode; }
|
||||||
CallGraphNode *getCallsExternalNode() const { return CallsExternalNode; }
|
|
||||||
|
|
||||||
/// Return the root/main method in the module, or some other root node, such
|
CallGraphNode *getCallsExternalNode() const { return CallsExternalNode; }
|
||||||
/// as the externalcallingnode.
|
|
||||||
CallGraphNode *getRoot() { return Root; }
|
|
||||||
const CallGraphNode *getRoot() const { return Root; }
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------
|
//===---------------------------------------------------------------------
|
||||||
// Functions to keep a call graph up to date with a function that has been
|
// Functions to keep a call graph up to date with a function that has been
|
||||||
// modified.
|
// modified.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// removeFunctionFromModule - Unlink the function from this module, returning
|
/// \brief Unlink the function from this module, returning it.
|
||||||
/// 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.
|
|
||||||
///
|
///
|
||||||
|
/// 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);
|
Function *removeFunctionFromModule(CallGraphNode *CGN);
|
||||||
|
|
||||||
/// getOrInsertFunction - This method is identical to calling operator[], but
|
/// \brief Similar to operator[], but this will insert a new CallGraphNode for
|
||||||
/// it will insert a new CallGraphNode for the specified function if one does
|
/// \c F if one does not already exist.
|
||||||
/// not already exist.
|
|
||||||
CallGraphNode *getOrInsertFunction(const Function *F);
|
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
/// \brief A node in the call graph for a module.
|
||||||
// CallGraphNode class definition.
|
///
|
||||||
//
|
/// 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 {
|
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:
|
public:
|
||||||
typedef std::pair<WeakVH, CallGraphNode*> CallRecord;
|
/// \brief A pair of the calling instruction (a call or invoke)
|
||||||
private:
|
/// and the call graph node being called.
|
||||||
std::vector<CallRecord> CalledFunctions;
|
typedef std::pair<WeakVH, CallGraphNode *> CallRecord;
|
||||||
|
|
||||||
/// NumReferences - This is 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; }
|
|
||||||
public:
|
public:
|
||||||
typedef std::vector<CallRecord> CalledFunctionsVector;
|
typedef std::vector<CallRecord> CalledFunctionsVector;
|
||||||
|
|
||||||
|
/// \brief Creates a node for the specified function.
|
||||||
// CallGraphNode ctor - Create a node for the specified function.
|
inline CallGraphNode(Function *F) : F(F), NumReferences(0) {}
|
||||||
inline CallGraphNode(Function *f) : F(f), NumReferences(0) {}
|
|
||||||
~CallGraphNode() {
|
~CallGraphNode() {
|
||||||
assert(NumReferences == 0 && "Node deleted while references remain");
|
assert(NumReferences == 0 && "Node deleted while references remain");
|
||||||
}
|
}
|
||||||
|
|
||||||
//===---------------------------------------------------------------------
|
|
||||||
// Accessor methods.
|
|
||||||
//
|
|
||||||
|
|
||||||
typedef std::vector<CallRecord>::iterator iterator;
|
typedef std::vector<CallRecord>::iterator iterator;
|
||||||
typedef std::vector<CallRecord>::const_iterator const_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; }
|
Function *getFunction() const { return F; }
|
||||||
|
|
||||||
inline iterator begin() { return CalledFunctions.begin(); }
|
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 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 bool empty() const { return CalledFunctions.empty(); }
|
||||||
inline unsigned size() const { return (unsigned)CalledFunctions.size(); }
|
inline unsigned size() const { return (unsigned)CalledFunctions.size(); }
|
||||||
|
|
||||||
/// getNumReferences - Return the number of other CallGraphNodes in this
|
/// \brief Returns the number of other CallGraphNodes in this CallGraph that
|
||||||
/// CallGraph that reference this node in their callee list.
|
/// reference this node in their callee list.
|
||||||
unsigned getNumReferences() const { return NumReferences; }
|
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 {
|
CallGraphNode *operator[](unsigned i) const {
|
||||||
assert(i < CalledFunctions.size() && "Invalid index");
|
assert(i < CalledFunctions.size() && "Invalid index");
|
||||||
return CalledFunctions[i].second;
|
return CalledFunctions[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// dump - Print out this call graph node.
|
/// \brief Print out this call graph node.
|
||||||
///
|
|
||||||
void dump() const;
|
void dump() const;
|
||||||
void print(raw_ostream &OS) const;
|
void print(raw_ostream &OS) const;
|
||||||
|
|
||||||
@ -239,29 +211,25 @@ public:
|
|||||||
// modified
|
// modified
|
||||||
//
|
//
|
||||||
|
|
||||||
/// removeAllCalledFunctions - As the name implies, this removes all edges
|
/// \brief Removes all edges from this CallGraphNode to any functions it
|
||||||
/// from this CallGraphNode to any functions it calls.
|
/// calls.
|
||||||
void removeAllCalledFunctions() {
|
void removeAllCalledFunctions() {
|
||||||
while (!CalledFunctions.empty()) {
|
while (!CalledFunctions.empty()) {
|
||||||
CalledFunctions.back().second->DropRef();
|
CalledFunctions.back().second->DropRef();
|
||||||
CalledFunctions.pop_back();
|
CalledFunctions.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stealCalledFunctionsFrom - Move all the callee information from N to this
|
/// \brief Moves all the callee information from N to this node.
|
||||||
/// node.
|
|
||||||
void stealCalledFunctionsFrom(CallGraphNode *N) {
|
void stealCalledFunctionsFrom(CallGraphNode *N) {
|
||||||
assert(CalledFunctions.empty() &&
|
assert(CalledFunctions.empty() &&
|
||||||
"Cannot steal callsite information if I already have some");
|
"Cannot steal callsite information if I already have some");
|
||||||
std::swap(CalledFunctions, N->CalledFunctions);
|
std::swap(CalledFunctions, N->CalledFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// addCalledFunction - Add a function to the list of functions called by this
|
/// \brief Adds a function to the list of functions called by this one.
|
||||||
/// one.
|
|
||||||
void addCalledFunction(CallSite CS, CallGraphNode *M) {
|
void addCalledFunction(CallSite CS, CallGraphNode *M) {
|
||||||
assert(!CS.getInstruction() ||
|
assert(!CS.getInstruction() || !CS.getCalledFunction() ||
|
||||||
!CS.getCalledFunction() ||
|
|
||||||
!CS.getCalledFunction()->isIntrinsic());
|
!CS.getCalledFunction()->isIntrinsic());
|
||||||
CalledFunctions.push_back(std::make_pair(CS.getInstruction(), M));
|
CalledFunctions.push_back(std::make_pair(CS.getInstruction(), M));
|
||||||
M->AddRef();
|
M->AddRef();
|
||||||
@ -272,32 +240,152 @@ public:
|
|||||||
*I = CalledFunctions.back();
|
*I = CalledFunctions.back();
|
||||||
CalledFunctions.pop_back();
|
CalledFunctions.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Removes the edge in the node for the specified call site.
|
||||||
/// removeCallEdgeFor - This method removes the edge in the node for the
|
///
|
||||||
/// specified call site. Note that this method takes linear time, so it
|
/// Note that this method takes linear time, so it should be used sparingly.
|
||||||
/// should be used sparingly.
|
|
||||||
void removeCallEdgeFor(CallSite CS);
|
void removeCallEdgeFor(CallSite CS);
|
||||||
|
|
||||||
/// removeAnyCallEdgeTo - This method removes all call edges from this node
|
/// \brief Removes all call edges from this node to the specified callee
|
||||||
/// to the specified callee function. This takes more time to execute than
|
/// function.
|
||||||
/// removeCallEdgeTo, so it should not be used unless necessary.
|
///
|
||||||
|
/// This takes more time to execute than removeCallEdgeTo, so it should not
|
||||||
|
/// be used unless necessary.
|
||||||
void removeAnyCallEdgeTo(CallGraphNode *Callee);
|
void removeAnyCallEdgeTo(CallGraphNode *Callee);
|
||||||
|
|
||||||
/// removeOneAbstractEdgeTo - Remove one edge associated with a null callsite
|
/// \brief Removes one edge associated with a null callsite from this node to
|
||||||
/// from this node to the specified callee function.
|
/// the specified callee function.
|
||||||
void removeOneAbstractEdgeTo(CallGraphNode *Callee);
|
void removeOneAbstractEdgeTo(CallGraphNode *Callee);
|
||||||
|
|
||||||
/// replaceCallEdge - This method replaces the edge in the node for the
|
/// \brief Replaces the edge in the node for the specified call site with a
|
||||||
/// specified call site with a new one. Note that this method takes linear
|
/// new one.
|
||||||
/// time, so it should be used sparingly.
|
///
|
||||||
|
/// Note that this method takes linear time, so it should be used sparingly.
|
||||||
void replaceCallEdge(CallSite CS, CallSite NewCS, CallGraphNode *NewNode);
|
void replaceCallEdge(CallSite CS, CallSite NewCS, CallGraphNode *NewNode);
|
||||||
|
|
||||||
/// allReferencesDropped - This is a special function that should only be
|
private:
|
||||||
/// used by the CallGraph class.
|
friend class CallGraph;
|
||||||
void allReferencesDropped() {
|
|
||||||
NumReferences = 0;
|
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
|
// Provide graph traits for tranversing call graphs using standard graph
|
||||||
// traversals.
|
// traversals.
|
||||||
template <> struct GraphTraits<CallGraphNode*> {
|
template <> struct GraphTraits<CallGraphNode *> {
|
||||||
typedef CallGraphNode NodeType;
|
typedef CallGraphNode NodeType;
|
||||||
|
|
||||||
typedef CallGraphNode::CallRecord CGNPairTy;
|
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; }
|
static NodeType *getEntryNode(CallGraphNode *CGN) { return CGN; }
|
||||||
|
|
||||||
@ -320,55 +409,54 @@ template <> struct GraphTraits<CallGraphNode*> {
|
|||||||
static inline ChildIteratorType child_begin(NodeType *N) {
|
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||||
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
|
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));
|
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
|
||||||
}
|
}
|
||||||
|
|
||||||
static CallGraphNode *CGNDeref(CGNPairTy P) {
|
static CallGraphNode *CGNDeref(CGNPairTy P) { return P.second; }
|
||||||
return P.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct GraphTraits<const CallGraphNode*> {
|
template <> struct GraphTraits<const CallGraphNode *> {
|
||||||
typedef const CallGraphNode NodeType;
|
typedef const CallGraphNode NodeType;
|
||||||
typedef NodeType::const_iterator ChildIteratorType;
|
typedef NodeType::const_iterator ChildIteratorType;
|
||||||
|
|
||||||
static NodeType *getEntryNode(const CallGraphNode *CGN) { return CGN; }
|
static NodeType *getEntryNode(const CallGraphNode *CGN) { return CGN; }
|
||||||
static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();}
|
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||||
static inline ChildIteratorType child_end (NodeType *N) { return N->end(); }
|
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) {
|
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::pair<const Function *, CallGraphNode *> PairTy;
|
||||||
typedef std::pointer_to_unary_function<PairTy, CallGraphNode&> DerefFun;
|
typedef std::pointer_to_unary_function<PairTy, CallGraphNode &> DerefFun;
|
||||||
|
|
||||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||||
typedef mapped_iterator<CallGraph::iterator, DerefFun> nodes_iterator;
|
typedef mapped_iterator<CallGraph::iterator, DerefFun> nodes_iterator;
|
||||||
static nodes_iterator nodes_begin(CallGraph *CG) {
|
static nodes_iterator nodes_begin(CallGraph *CG) {
|
||||||
return map_iterator(CG->begin(), DerefFun(CGdereference));
|
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));
|
return map_iterator(CG->end(), DerefFun(CGdereference));
|
||||||
}
|
}
|
||||||
|
|
||||||
static CallGraphNode &CGdereference(PairTy P) {
|
static CallGraphNode &CGdereference(PairTy P) { return *P.second; }
|
||||||
return *P.second;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct GraphTraits<const CallGraph*> :
|
template <>
|
||||||
public GraphTraits<const CallGraphNode*> {
|
struct GraphTraits<const CallGraph *> : public GraphTraits<
|
||||||
|
const CallGraphNode *> {
|
||||||
static NodeType *getEntryNode(const CallGraph *CGN) {
|
static NodeType *getEntryNode(const CallGraph *CGN) {
|
||||||
return CGN->getExternalCallingNode();
|
return CGN->getExternalCallingNode();
|
||||||
}
|
}
|
||||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||||
typedef CallGraph::const_iterator nodes_iterator;
|
typedef CallGraph::const_iterator nodes_iterator;
|
||||||
static nodes_iterator nodes_begin(const CallGraph *CG) { return CG->begin(); }
|
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
|
} // End llvm namespace
|
||||||
|
@ -37,7 +37,8 @@ public:
|
|||||||
|
|
||||||
/// createPrinterPass - Get a pass that prints the Module
|
/// createPrinterPass - Get a pass that prints the Module
|
||||||
/// corresponding to a CallGraph.
|
/// 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::doInitialization;
|
||||||
using llvm::Pass::doFinalization;
|
using llvm::Pass::doFinalization;
|
||||||
@ -65,18 +66,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Assign pass manager to manager this pass
|
/// Assign pass manager to manager this pass
|
||||||
virtual void assignPassManager(PMStack &PMS,
|
void assignPassManager(PMStack &PMS, PassManagerType PMT) override;
|
||||||
PassManagerType PMT);
|
|
||||||
|
|
||||||
/// Return what kind of Pass Manager can manage this pass.
|
/// Return what kind of Pass Manager can manage this pass.
|
||||||
virtual PassManagerType getPotentialPassManagerType() const {
|
PassManagerType getPotentialPassManagerType() const override {
|
||||||
return PMT_CallGraphPassManager;
|
return PMT_CallGraphPassManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getAnalysisUsage - For this class, we declare that we require and preserve
|
/// getAnalysisUsage - For this class, we declare that we require and preserve
|
||||||
/// the call graph. If the derived class implements this method, it should
|
/// the call graph. If the derived class implements this method, it should
|
||||||
/// always explicitly call the implementation here.
|
/// 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.
|
/// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
|
||||||
|
@ -18,6 +18,8 @@ namespace llvm {
|
|||||||
|
|
||||||
class Value;
|
class Value;
|
||||||
class Use;
|
class Use;
|
||||||
|
class Instruction;
|
||||||
|
class DominatorTree;
|
||||||
|
|
||||||
/// PointerMayBeCaptured - Return true if this pointer value may be captured
|
/// PointerMayBeCaptured - Return true if this pointer value may be captured
|
||||||
/// by the enclosing function (which is required to exist). This routine can
|
/// by the enclosing function (which is required to exist). This routine can
|
||||||
@ -30,6 +32,20 @@ namespace llvm {
|
|||||||
bool ReturnCaptures,
|
bool ReturnCaptures,
|
||||||
bool StoreCaptures);
|
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
|
/// This callback is used in conjunction with PointerMayBeCaptured. In
|
||||||
/// addition to the interface here, you'll need to provide your own getters
|
/// addition to the interface here, you'll need to provide your own getters
|
||||||
/// to see whether anything was captured.
|
/// to see whether anything was captured.
|
||||||
@ -45,12 +61,12 @@ namespace llvm {
|
|||||||
/// capture) return false. To search it, return true.
|
/// capture) return false. To search it, return true.
|
||||||
///
|
///
|
||||||
/// U->getUser() is always an Instruction.
|
/// 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
|
/// captured - Information about the pointer was captured by the user of
|
||||||
/// use U. Return true to stop the traversal or false to continue looking
|
/// use U. Return true to stop the traversal or false to continue looking
|
||||||
/// for more capturing instructions.
|
/// 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
|
/// PointerMayBeCaptured - Visit the value and the values derived from it and
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#define LLVM_ANALYSIS_CODEMETRICS_H
|
#define LLVM_ANALYSIS_CODEMETRICS_H
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/Support/CallSite.h"
|
#include "llvm/IR/CallSite.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class BasicBlock;
|
class BasicBlock;
|
||||||
|
@ -36,15 +36,16 @@ namespace llvm {
|
|||||||
/// Note that this fails if not all of the operands are constant. Otherwise,
|
/// 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
|
/// this function can only fail when attempting to fold instructions like loads
|
||||||
/// and stores, which have no constant expression form.
|
/// and stores, which have no constant expression form.
|
||||||
Constant *ConstantFoldInstruction(Instruction *I, const DataLayout *TD = 0,
|
Constant *ConstantFoldInstruction(Instruction *I,
|
||||||
const TargetLibraryInfo *TLI = 0);
|
const DataLayout *TD = nullptr,
|
||||||
|
const TargetLibraryInfo *TLI = nullptr);
|
||||||
|
|
||||||
/// ConstantFoldConstantExpression - Attempt to fold the constant expression
|
/// ConstantFoldConstantExpression - Attempt to fold the constant expression
|
||||||
/// using the specified DataLayout. If successful, the constant result is
|
/// using the specified DataLayout. If successful, the constant result is
|
||||||
/// result is returned, if not, null is returned.
|
/// result is returned, if not, null is returned.
|
||||||
Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
|
Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0);
|
const TargetLibraryInfo *TLI =nullptr);
|
||||||
|
|
||||||
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
|
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
|
||||||
/// specified operands. If successful, the constant result is returned, if not,
|
/// 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,
|
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
|
||||||
ArrayRef<Constant *> Ops,
|
ArrayRef<Constant *> Ops,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0);
|
const TargetLibraryInfo *TLI = nullptr);
|
||||||
|
|
||||||
/// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
|
/// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
|
||||||
/// instruction (icmp/fcmp) with the specified operands. If it fails, it
|
/// 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 *ConstantFoldCompareInstOperands(unsigned Predicate,
|
||||||
Constant *LHS, Constant *RHS,
|
Constant *LHS, Constant *RHS,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0);
|
const TargetLibraryInfo *TLI=nullptr);
|
||||||
|
|
||||||
/// ConstantFoldInsertValueInstruction - Attempt to constant fold an insertvalue
|
/// ConstantFoldInsertValueInstruction - Attempt to constant fold an insertvalue
|
||||||
/// instruction with the specified operands and indices. The constant result is
|
/// 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
|
/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would
|
||||||
/// produce if it is constant and determinable. If this is not determinable,
|
/// produce if it is constant and determinable. If this is not determinable,
|
||||||
/// return null.
|
/// return null.
|
||||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout *TD = 0);
|
Constant *ConstantFoldLoadFromConstPtr(Constant *C,
|
||||||
|
const DataLayout *TD = nullptr);
|
||||||
|
|
||||||
/// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a
|
/// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a
|
||||||
/// getelementptr constantexpr, return the constant value being addressed by the
|
/// 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
|
/// ConstantFoldCall - Attempt to constant fold a call to the specified function
|
||||||
/// with the specified arguments, returning null if unsuccessful.
|
/// with the specified arguments, returning null if unsuccessful.
|
||||||
Constant *ConstantFoldCall(Function *F, ArrayRef<Constant *> Operands,
|
Constant *ConstantFoldCall(Function *F, ArrayRef<Constant *> Operands,
|
||||||
const TargetLibraryInfo *TLI = 0);
|
const TargetLibraryInfo *TLI = nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#ifndef LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
#ifndef LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
||||||
#define LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
#define LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
||||||
|
|
||||||
#include "llvm/Support/InstIterator.h"
|
#include "llvm/IR/InstIterator.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
@ -16,53 +16,66 @@
|
|||||||
|
|
||||||
#include "llvm/Analysis/CFGPrinter.h"
|
#include "llvm/Analysis/CFGPrinter.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
|
||||||
namespace llvm {
|
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 {
|
class DOTGraphTraitsViewer : public FunctionPass {
|
||||||
public:
|
public:
|
||||||
DOTGraphTraitsViewer(StringRef GraphName, char &ID)
|
DOTGraphTraitsViewer(StringRef GraphName, char &ID)
|
||||||
: FunctionPass(ID), Name(GraphName) {}
|
: FunctionPass(ID), Name(GraphName) {}
|
||||||
|
|
||||||
virtual bool runOnFunction(Function &F) {
|
bool runOnFunction(Function &F) override {
|
||||||
Analysis *Graph = &getAnalysis<Analysis>();
|
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||||
std::string GraphName = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||||
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
||||||
|
|
||||||
ViewGraph(Graph, Name, Simple, Title);
|
ViewGraph(Graph, Name, IsSimple, Title);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
AU.addRequired<Analysis>();
|
AU.addRequired<AnalysisT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string Name;
|
std::string Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Analysis, bool Simple>
|
template <
|
||||||
|
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||||
|
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||||
class DOTGraphTraitsPrinter : public FunctionPass {
|
class DOTGraphTraitsPrinter : public FunctionPass {
|
||||||
public:
|
public:
|
||||||
DOTGraphTraitsPrinter(StringRef GraphName, char &ID)
|
DOTGraphTraitsPrinter(StringRef GraphName, char &ID)
|
||||||
: FunctionPass(ID), Name(GraphName) {}
|
: FunctionPass(ID), Name(GraphName) {}
|
||||||
|
|
||||||
virtual bool runOnFunction(Function &F) {
|
bool runOnFunction(Function &F) override {
|
||||||
Analysis *Graph = &getAnalysis<Analysis>();
|
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||||
std::string Filename = Name + "." + F.getName().str() + ".dot";
|
std::string Filename = Name + "." + F.getName().str() + ".dot";
|
||||||
std::string ErrorInfo;
|
std::string ErrorInfo;
|
||||||
|
|
||||||
errs() << "Writing '" << Filename << "'...";
|
errs() << "Writing '" << Filename << "'...";
|
||||||
|
|
||||||
raw_fd_ostream File(Filename.c_str(), ErrorInfo);
|
raw_fd_ostream File(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
|
||||||
std::string GraphName = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||||
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
||||||
|
|
||||||
if (ErrorInfo.empty())
|
if (ErrorInfo.empty())
|
||||||
WriteGraph(File, Graph, Simple, Title);
|
WriteGraph(File, Graph, IsSimple, Title);
|
||||||
else
|
else
|
||||||
errs() << " error opening file for writing!";
|
errs() << " error opening file for writing!";
|
||||||
errs() << "\n";
|
errs() << "\n";
|
||||||
@ -70,57 +83,61 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
AU.addRequired<Analysis>();
|
AU.addRequired<AnalysisT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string Name;
|
std::string Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Analysis, bool Simple>
|
template <
|
||||||
|
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||||
|
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||||
class DOTGraphTraitsModuleViewer : public ModulePass {
|
class DOTGraphTraitsModuleViewer : public ModulePass {
|
||||||
public:
|
public:
|
||||||
DOTGraphTraitsModuleViewer(StringRef GraphName, char &ID)
|
DOTGraphTraitsModuleViewer(StringRef GraphName, char &ID)
|
||||||
: ModulePass(ID), Name(GraphName) {}
|
: ModulePass(ID), Name(GraphName) {}
|
||||||
|
|
||||||
virtual bool runOnModule(Module &M) {
|
bool runOnModule(Module &M) override {
|
||||||
Analysis *Graph = &getAnalysis<Analysis>();
|
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||||
std::string Title = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||||
|
|
||||||
ViewGraph(Graph, Name, Simple, Title);
|
ViewGraph(Graph, Name, IsSimple, Title);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
AU.addRequired<Analysis>();
|
AU.addRequired<AnalysisT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string Name;
|
std::string Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Analysis, bool Simple>
|
template <
|
||||||
|
typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
|
||||||
|
typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT> >
|
||||||
class DOTGraphTraitsModulePrinter : public ModulePass {
|
class DOTGraphTraitsModulePrinter : public ModulePass {
|
||||||
public:
|
public:
|
||||||
DOTGraphTraitsModulePrinter(StringRef GraphName, char &ID)
|
DOTGraphTraitsModulePrinter(StringRef GraphName, char &ID)
|
||||||
: ModulePass(ID), Name(GraphName) {}
|
: ModulePass(ID), Name(GraphName) {}
|
||||||
|
|
||||||
virtual bool runOnModule(Module &M) {
|
bool runOnModule(Module &M) override {
|
||||||
Analysis *Graph = &getAnalysis<Analysis>();
|
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
|
||||||
std::string Filename = Name + ".dot";
|
std::string Filename = Name + ".dot";
|
||||||
std::string ErrorInfo;
|
std::string ErrorInfo;
|
||||||
|
|
||||||
errs() << "Writing '" << Filename << "'...";
|
errs() << "Writing '" << Filename << "'...";
|
||||||
|
|
||||||
raw_fd_ostream File(Filename.c_str(), ErrorInfo);
|
raw_fd_ostream File(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
|
||||||
std::string Title = DOTGraphTraits<Analysis*>::getGraphName(Graph);
|
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||||
|
|
||||||
if (ErrorInfo.empty())
|
if (ErrorInfo.empty())
|
||||||
WriteGraph(File, Graph, Simple, Title);
|
WriteGraph(File, Graph, IsSimple, Title);
|
||||||
else
|
else
|
||||||
errs() << " error opening file for writing!";
|
errs() << " error opening file for writing!";
|
||||||
errs() << "\n";
|
errs() << "\n";
|
||||||
@ -128,9 +145,9 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
AU.addRequired<Analysis>();
|
AU.addRequired<AnalysisT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -73,8 +73,8 @@ namespace llvm {
|
|||||||
Instruction *Destination) :
|
Instruction *Destination) :
|
||||||
Src(Source),
|
Src(Source),
|
||||||
Dst(Destination),
|
Dst(Destination),
|
||||||
NextPredecessor(NULL),
|
NextPredecessor(nullptr),
|
||||||
NextSuccessor(NULL) {}
|
NextSuccessor(nullptr) {}
|
||||||
virtual ~Dependence() {}
|
virtual ~Dependence() {}
|
||||||
|
|
||||||
/// Dependence::DVEntry - Each level in the distance/direction vector
|
/// Dependence::DVEntry - Each level in the distance/direction vector
|
||||||
@ -96,7 +96,7 @@ namespace llvm {
|
|||||||
bool Splitable : 1; // Splitting the loop will break dependence.
|
bool Splitable : 1; // Splitting the loop will break dependence.
|
||||||
const SCEV *Distance; // NULL implies no distance available.
|
const SCEV *Distance; // NULL implies no distance available.
|
||||||
DVEntry() : Direction(ALL), Scalar(true), PeelFirst(false),
|
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.
|
/// getSrc - Returns the source instruction for this dependence.
|
||||||
@ -154,7 +154,7 @@ namespace llvm {
|
|||||||
|
|
||||||
/// getDistance - Returns the distance (or NULL) associated with a
|
/// getDistance - Returns the distance (or NULL) associated with a
|
||||||
/// particular level.
|
/// 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
|
/// isPeelFirst - Returns true if peeling the first iteration from
|
||||||
/// this loop will break this dependence.
|
/// this loop will break this dependence.
|
||||||
@ -227,45 +227,45 @@ namespace llvm {
|
|||||||
|
|
||||||
/// isLoopIndependent - Returns true if this is a loop-independent
|
/// isLoopIndependent - Returns true if this is a loop-independent
|
||||||
/// dependence.
|
/// dependence.
|
||||||
bool isLoopIndependent() const { return LoopIndependent; }
|
bool isLoopIndependent() const override { return LoopIndependent; }
|
||||||
|
|
||||||
/// isConfused - Returns true if this dependence is confused
|
/// isConfused - Returns true if this dependence is confused
|
||||||
/// (the compiler understands nothing and makes worst-case
|
/// (the compiler understands nothing and makes worst-case
|
||||||
/// assumptions).
|
/// assumptions).
|
||||||
bool isConfused() const { return false; }
|
bool isConfused() const override { return false; }
|
||||||
|
|
||||||
/// isConsistent - Returns true if this dependence is consistent
|
/// isConsistent - Returns true if this dependence is consistent
|
||||||
/// (occurs every time the source and destination are executed).
|
/// (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
|
/// getLevels - Returns the number of common loops surrounding the
|
||||||
/// source and destination of the dependence.
|
/// 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
|
/// getDirection - Returns the direction associated with a particular
|
||||||
/// level.
|
/// level.
|
||||||
unsigned getDirection(unsigned Level) const;
|
unsigned getDirection(unsigned Level) const override;
|
||||||
|
|
||||||
/// getDistance - Returns the distance (or NULL) associated with a
|
/// getDistance - Returns the distance (or NULL) associated with a
|
||||||
/// particular level.
|
/// particular level.
|
||||||
const SCEV *getDistance(unsigned Level) const;
|
const SCEV *getDistance(unsigned Level) const override;
|
||||||
|
|
||||||
/// isPeelFirst - Returns true if peeling the first iteration from
|
/// isPeelFirst - Returns true if peeling the first iteration from
|
||||||
/// this loop will break this dependence.
|
/// 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
|
/// isPeelLast - Returns true if peeling the last iteration from
|
||||||
/// this loop will break this dependence.
|
/// 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
|
/// isSplitable - Returns true if splitting the loop will break
|
||||||
/// the dependence.
|
/// the dependence.
|
||||||
bool isSplitable(unsigned Level) const;
|
bool isSplitable(unsigned Level) const override;
|
||||||
|
|
||||||
/// isScalar - Returns true if a particular level is scalar; that is,
|
/// isScalar - Returns true if a particular level is scalar; that is,
|
||||||
/// if no subscript in the source or destination mention the induction
|
/// if no subscript in the source or destination mention the induction
|
||||||
/// variable associated with the loop at this level.
|
/// variable associated with the loop at this level.
|
||||||
bool isScalar(unsigned Level) const;
|
bool isScalar(unsigned Level) const override;
|
||||||
private:
|
private:
|
||||||
unsigned short Levels;
|
unsigned short Levels;
|
||||||
bool LoopIndependent;
|
bool LoopIndependent;
|
||||||
@ -910,7 +910,8 @@ namespace llvm {
|
|||||||
const Constraint &CurConstraint) const;
|
const Constraint &CurConstraint) const;
|
||||||
|
|
||||||
bool tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
|
bool tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
|
||||||
SmallVectorImpl<Subscript> &Pair) const;
|
SmallVectorImpl<Subscript> &Pair,
|
||||||
|
const SCEV *ElementSize) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Class identification, replacement for typeinfo
|
static char ID; // Class identification, replacement for typeinfo
|
||||||
@ -918,10 +919,10 @@ namespace llvm {
|
|||||||
initializeDependenceAnalysisPass(*PassRegistry::getPassRegistry());
|
initializeDependenceAnalysisPass(*PassRegistry::getPassRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F) override;
|
||||||
void releaseMemory();
|
void releaseMemory() override;
|
||||||
void getAnalysisUsage(AnalysisUsage &) const;
|
void getAnalysisUsage(AnalysisUsage &) const override;
|
||||||
void print(raw_ostream &, const Module * = 0) const;
|
void print(raw_ostream &, const Module * = nullptr) const override;
|
||||||
}; // class DependenceAnalysis
|
}; // class DependenceAnalysis
|
||||||
|
|
||||||
/// createDependenceAnalysisPass - This creates an instance of the
|
/// createDependenceAnalysisPass - This creates an instance of the
|
||||||
|
@ -18,173 +18,191 @@
|
|||||||
#ifndef LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
#ifndef LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
||||||
#define LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
#define LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
||||||
|
|
||||||
#include "llvm/Analysis/Dominators.h"
|
#include "llvm/IR/Dominators.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
/// DominanceFrontierBase - Common base class for computing forward and inverse
|
/// DominanceFrontierBase - Common base class for computing forward and inverse
|
||||||
/// dominance frontiers for a function.
|
/// dominance frontiers for a function.
|
||||||
///
|
///
|
||||||
class DominanceFrontierBase : public FunctionPass {
|
template <class BlockT>
|
||||||
|
class DominanceFrontierBase {
|
||||||
public:
|
public:
|
||||||
typedef std::set<BasicBlock*> DomSetType; // Dom set for a bb
|
typedef std::set<BlockT *> DomSetType; // Dom set for a bb
|
||||||
typedef std::map<BasicBlock*, DomSetType> DomSetMapType; // Dom set map
|
typedef std::map<BlockT *, DomSetType> DomSetMapType; // Dom set map
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
typedef GraphTraits<BlockT *> BlockTraits;
|
||||||
|
|
||||||
DomSetMapType Frontiers;
|
DomSetMapType Frontiers;
|
||||||
std::vector<BasicBlock*> Roots;
|
std::vector<BlockT *> Roots;
|
||||||
const bool IsPostDominators;
|
const bool IsPostDominators;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DominanceFrontierBase(char &ID, bool isPostDom)
|
DominanceFrontierBase(bool isPostDom) : IsPostDominators(isPostDom) {}
|
||||||
: FunctionPass(ID), IsPostDominators(isPostDom) {}
|
|
||||||
|
|
||||||
/// getRoots - Return the root blocks of the current CFG. This may include
|
/// getRoots - Return the root blocks of the current CFG. This may include
|
||||||
/// multiple blocks if we are computing post dominators. For forward
|
/// multiple blocks if we are computing post dominators. For forward
|
||||||
/// dominators, this will always be a single block (the entry node).
|
/// 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
|
/// 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:
|
// Accessor interface:
|
||||||
typedef DomSetMapType::iterator iterator;
|
typedef typename DomSetMapType::iterator iterator;
|
||||||
typedef DomSetMapType::const_iterator const_iterator;
|
typedef typename DomSetMapType::const_iterator const_iterator;
|
||||||
iterator begin() { return Frontiers.begin(); }
|
iterator begin() { return Frontiers.begin(); }
|
||||||
const_iterator begin() const { return Frontiers.begin(); }
|
const_iterator begin() const { return Frontiers.begin(); }
|
||||||
iterator end() { return Frontiers.end(); }
|
iterator end() { return Frontiers.end(); }
|
||||||
const_iterator end() const { return Frontiers.end(); }
|
const_iterator end() const { return Frontiers.end(); }
|
||||||
iterator find(BasicBlock *B) { return Frontiers.find(B); }
|
iterator find(BlockT *B) { return Frontiers.find(B); }
|
||||||
const_iterator find(BasicBlock *B) const { 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!");
|
assert(find(BB) == end() && "Block already in DominanceFrontier!");
|
||||||
return Frontiers.insert(std::make_pair(BB, frontier)).first;
|
return Frontiers.insert(std::make_pair(BB, frontier)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// removeBlock - Remove basic block BB's frontier.
|
/// removeBlock - Remove basic block BB's frontier.
|
||||||
void removeBlock(BasicBlock *BB) {
|
void 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToFrontier(iterator I, BasicBlock *Node) {
|
void addToFrontier(iterator I, BlockT *Node);
|
||||||
assert(I != end() && "BB is not in DominanceFrontier!");
|
|
||||||
I->second.insert(Node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeFromFrontier(iterator I, BasicBlock *Node) {
|
void 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// compareDomSet - Return false if two domsets match. Otherwise
|
/// compareDomSet - Return false if two domsets match. Otherwise
|
||||||
/// return true;
|
/// return true;
|
||||||
bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// compare - Return true if the other dominance frontier base matches
|
/// compare - Return true if the other dominance frontier base matches
|
||||||
/// this dominance frontier base. Otherwise return false.
|
/// this dominance frontier base. Otherwise return false.
|
||||||
bool compare(DominanceFrontierBase &Other) const {
|
bool compare(DominanceFrontierBase<BlockT> &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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// print - Convert to human readable form
|
/// 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().
|
/// dump - Dump the dominance frontier to dbgs().
|
||||||
void dump() const;
|
void dump() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//===-------------------------------------
|
//===-------------------------------------
|
||||||
/// DominanceFrontier Class - Concrete subclass of DominanceFrontierBase that is
|
/// DominanceFrontier Class - Concrete subclass of DominanceFrontierBase that is
|
||||||
/// used to compute a forward dominator frontiers.
|
/// used to compute a forward dominator frontiers.
|
||||||
///
|
///
|
||||||
class DominanceFrontier : public DominanceFrontierBase {
|
template <class BlockT>
|
||||||
virtual void anchor();
|
class ForwardDominanceFrontierBase : public DominanceFrontierBase<BlockT> {
|
||||||
|
private:
|
||||||
|
typedef GraphTraits<BlockT *> BlockTraits;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Pass ID, replacement for typeid
|
typedef DominatorTreeBase<BlockT> DomTreeT;
|
||||||
DominanceFrontier() :
|
typedef DomTreeNodeBase<BlockT> DomTreeNodeT;
|
||||||
DominanceFrontierBase(ID, false) {
|
typedef typename DominanceFrontierBase<BlockT>::DomSetType DomSetType;
|
||||||
initializeDominanceFrontierPass(*PassRegistry::getPassRegistry());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicBlock *getRoot() const {
|
ForwardDominanceFrontierBase() : DominanceFrontierBase<BlockT>(false) {}
|
||||||
assert(Roots.size() == 1 && "Should always have entry node!");
|
|
||||||
return Roots[0];
|
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 &) {
|
const DomSetType &calculate(const DomTreeT &DT, const DomTreeNodeT *Node);
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
} // End llvm namespace
|
||||||
|
|
||||||
#endif
|
#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
|
/// passed in, then the types are printed symbolically if possible, using the
|
||||||
/// symbol table from the module.
|
/// 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:
|
private:
|
||||||
/// IncorporateType - Incorporate one type and all of its subtypes into the
|
/// IncorporateType - Incorporate one type and all of its subtypes into the
|
||||||
@ -53,10 +53,10 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// run - This incorporates all types used by the specified module
|
/// 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.
|
/// getAnalysisUsage - We do not modify anything.
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "llvm/Analysis/LoopPass.h"
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
#include "llvm/Analysis/ScalarEvolutionNormalization.h"
|
#include "llvm/Analysis/ScalarEvolutionNormalization.h"
|
||||||
#include "llvm/Support/ValueHandle.h"
|
#include "llvm/IR/ValueHandle.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ private:
|
|||||||
|
|
||||||
/// Deleted - Implementation of CallbackVH virtual function to
|
/// Deleted - Implementation of CallbackVH virtual function to
|
||||||
/// receive notification when the User is deleted.
|
/// receive notification when the User is deleted.
|
||||||
virtual void deleted();
|
void deleted() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct ilist_traits<IVStrideUse>
|
template<> struct ilist_traits<IVStrideUse>
|
||||||
@ -122,18 +122,18 @@ class IVUsers : public LoopPass {
|
|||||||
LoopInfo *LI;
|
LoopInfo *LI;
|
||||||
DominatorTree *DT;
|
DominatorTree *DT;
|
||||||
ScalarEvolution *SE;
|
ScalarEvolution *SE;
|
||||||
DataLayout *TD;
|
const DataLayout *DL;
|
||||||
SmallPtrSet<Instruction*,16> Processed;
|
SmallPtrSet<Instruction*,16> Processed;
|
||||||
|
|
||||||
/// IVUses - A list of all tracked IV uses of induction variable expressions
|
/// IVUses - A list of all tracked IV uses of induction variable expressions
|
||||||
/// we are interested in.
|
/// we are interested in.
|
||||||
ilist<IVStrideUse> IVUses;
|
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:
|
public:
|
||||||
static char ID; // Pass ID, replacement for typeid
|
static char ID; // Pass ID, replacement for typeid
|
||||||
@ -169,7 +169,7 @@ public:
|
|||||||
return Processed.count(Inst);
|
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.
|
/// dump - This method is used for debugging.
|
||||||
void dump() const;
|
void dump() const;
|
||||||
|
@ -99,7 +99,6 @@ public:
|
|||||||
|
|
||||||
/// \brief Cost analyzer used by inliner.
|
/// \brief Cost analyzer used by inliner.
|
||||||
class InlineCostAnalysis : public CallGraphSCCPass {
|
class InlineCostAnalysis : public CallGraphSCCPass {
|
||||||
const DataLayout *TD;
|
|
||||||
const TargetTransformInfo *TTI;
|
const TargetTransformInfo *TTI;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -109,8 +108,8 @@ public:
|
|||||||
~InlineCostAnalysis();
|
~InlineCostAnalysis();
|
||||||
|
|
||||||
// Pass interface implementation.
|
// Pass interface implementation.
|
||||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||||
bool runOnSCC(CallGraphSCC &SCC);
|
bool runOnSCC(CallGraphSCC &SCC) override;
|
||||||
|
|
||||||
/// \brief Get an InlineCost object representing the cost of inlining this
|
/// \brief Get an InlineCost object representing the cost of inlining this
|
||||||
/// callsite.
|
/// callsite.
|
||||||
|
@ -48,160 +48,166 @@ namespace llvm {
|
|||||||
/// SimplifyAddInst - Given operands for an Add, see if we can
|
/// SimplifyAddInst - Given operands for an Add, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifySubInst - Given operands for a Sub, see if we can
|
/// SimplifySubInst - Given operands for a Sub, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// Given operands for an FAdd, see if we can fold the result. If not, this
|
/// Given operands for an FAdd, see if we can fold the result. If not, this
|
||||||
/// returns null.
|
/// returns null.
|
||||||
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// Given operands for an FSub, see if we can fold the result. If not, this
|
/// Given operands for an FSub, see if we can fold the result. If not, this
|
||||||
/// returns null.
|
/// returns null.
|
||||||
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// Given operands for an FMul, see if we can fold the result. If not, this
|
/// Given operands for an FMul, see if we can fold the result. If not, this
|
||||||
/// returns null.
|
/// returns null.
|
||||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS,
|
Value *SimplifyFMulInst(Value *LHS, Value *RHS,
|
||||||
FastMathFlags FMF,
|
FastMathFlags FMF,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyMulInst - Given operands for a Mul, see if we can
|
/// SimplifyMulInst - Given operands for a Mul, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifySDivInst - Given operands for an SDiv, see if we can
|
/// SimplifySDivInst - Given operands for an SDiv, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifySDivInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifySDivInst(Value *LHS, Value *RHS,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
|
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyUDivInst(Value *LHS, Value *RHS,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyFDivInst - Given operands for an FDiv, see if we can
|
/// SimplifyFDivInst - Given operands for an FDiv, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyFDivInst(Value *LHS, Value *RHS,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifySRemInst - Given operands for an SRem, see if we can
|
/// SimplifySRemInst - Given operands for an SRem, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifySRemInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifySRemInst(Value *LHS, Value *RHS,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyURemInst - Given operands for a URem, see if we can
|
/// SimplifyURemInst - Given operands for a URem, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyURemInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyURemInst(Value *LHS, Value *RHS,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyFRemInst - Given operands for an FRem, see if we can
|
/// SimplifyFRemInst - Given operands for an FRem, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyFRemInst(Value *LHS, Value *RHS,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyShlInst - Given operands for a Shl, see if we can
|
/// SimplifyShlInst - Given operands for a Shl, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyLShrInst - Given operands for a LShr, see if we can
|
/// SimplifyLShrInst - Given operands for a LShr, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyAShrInst - Given operands for a AShr, see if we can
|
/// SimplifyAShrInst - Given operands for a AShr, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyAndInst - Given operands for an And, see if we can
|
/// SimplifyAndInst - Given operands for an And, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyOrInst - Given operands for an Or, see if we can
|
/// SimplifyOrInst - Given operands for an Or, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyXorInst - Given operands for a Xor, see if we can
|
/// SimplifyXorInst - Given operands for a Xor, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout *TD = 0,
|
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
|
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
|
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
|
||||||
/// the result. If not, this returns null.
|
/// the result. If not, this returns null.
|
||||||
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
|
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout *TD = 0,
|
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
|
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
|
||||||
/// can fold the result. If not, this returns null.
|
/// can fold the result. If not, this returns null.
|
||||||
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||||
ArrayRef<unsigned> Idxs,
|
ArrayRef<unsigned> Idxs,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyTruncInst - Given operands for an TruncInst, see if we can fold
|
/// SimplifyTruncInst - Given operands for an TruncInst, see if we can fold
|
||||||
/// the result. If not, this returns null.
|
/// the result. If not, this returns null.
|
||||||
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout *TD = 0,
|
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
//=== Helper functions for higher up the class hierarchy.
|
//=== Helper functions for higher up the class hierarchy.
|
||||||
|
|
||||||
@ -209,40 +215,40 @@ namespace llvm {
|
|||||||
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
|
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
|
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// \brief Given a function and iterators over arguments, see if we can fold
|
/// \brief Given a function and iterators over arguments, see if we can fold
|
||||||
/// the result.
|
/// the result.
|
||||||
///
|
///
|
||||||
/// If this call could not be simplified returns null.
|
/// If this call could not be simplified returns null.
|
||||||
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
||||||
User::op_iterator ArgEnd, const DataLayout *TD = 0,
|
User::op_iterator ArgEnd, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// \brief Given a function and set of arguments, see if we can fold the
|
/// \brief Given a function and set of arguments, see if we can fold the
|
||||||
/// result.
|
/// result.
|
||||||
///
|
///
|
||||||
/// If this call could not be simplified returns null.
|
/// If this call could not be simplified returns null.
|
||||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args,
|
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// SimplifyInstruction - See if we can compute a simplified version of this
|
/// SimplifyInstruction - See if we can compute a simplified version of this
|
||||||
/// instruction. If not, this returns null.
|
/// instruction. If not, this returns null.
|
||||||
Value *SimplifyInstruction(Instruction *I, const DataLayout *TD = 0,
|
Value *SimplifyInstruction(Instruction *I, const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
|
|
||||||
/// \brief Replace all uses of 'I' with 'SimpleV' and simplify the uses
|
/// \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.
|
/// The function returns true if any simplifications were performed.
|
||||||
bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV,
|
bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
|
|
||||||
/// \brief Recursively attempt to simplify an instruction.
|
/// \brief Recursively attempt to simplify an instruction.
|
||||||
///
|
///
|
||||||
@ -265,9 +271,9 @@ namespace llvm {
|
|||||||
/// of the users impacted. It returns true if any simplifications were
|
/// of the users impacted. It returns true if any simplifications were
|
||||||
/// performed.
|
/// performed.
|
||||||
bool recursivelySimplifyInstruction(Instruction *I,
|
bool recursivelySimplifyInstruction(Instruction *I,
|
||||||
const DataLayout *TD = 0,
|
const DataLayout *TD = nullptr,
|
||||||
const TargetLibraryInfo *TLI = 0,
|
const TargetLibraryInfo *TLI = nullptr,
|
||||||
const DominatorTree *DT = 0);
|
const DominatorTree *DT = nullptr);
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,9 +48,6 @@ public:
|
|||||||
Nodes.push_back(Header);
|
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; }
|
inline BasicBlock *getHeaderNode() const { return HeaderNode; }
|
||||||
|
|
||||||
/// Nodes - The basic blocks in this interval.
|
/// Nodes - The basic blocks in this interval.
|
||||||
|
@ -34,8 +34,8 @@
|
|||||||
#define LLVM_ANALYSIS_INTERVALITERATOR_H
|
#define LLVM_ANALYSIS_INTERVALITERATOR_H
|
||||||
|
|
||||||
#include "llvm/Analysis/IntervalPartition.h"
|
#include "llvm/Analysis/IntervalPartition.h"
|
||||||
|
#include "llvm/IR/CFG.h"
|
||||||
#include "llvm/IR/Function.h"
|
#include "llvm/IR/Function.h"
|
||||||
#include "llvm/Support/CFG.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -34,7 +34,7 @@ namespace llvm {
|
|||||||
// IntervalPartition - This class builds and holds an "interval partition" for
|
// IntervalPartition - This class builds and holds an "interval partition" for
|
||||||
// a function. This partition divides the control flow graph into a set of
|
// a function. This partition divides the control flow graph into a set of
|
||||||
// maximal intervals, as defined with the properties above. Intuitively, an
|
// 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.
|
// nodes following it.
|
||||||
//
|
//
|
||||||
class IntervalPartition : public FunctionPass {
|
class IntervalPartition : public FunctionPass {
|
||||||
@ -48,12 +48,12 @@ class IntervalPartition : public FunctionPass {
|
|||||||
public:
|
public:
|
||||||
static char ID; // Pass identification, replacement for typeid
|
static char ID; // Pass identification, replacement for typeid
|
||||||
|
|
||||||
IntervalPartition() : FunctionPass(ID), RootInterval(0) {
|
IntervalPartition() : FunctionPass(ID), RootInterval(nullptr) {
|
||||||
initializeIntervalPartitionPass(*PassRegistry::getPassRegistry());
|
initializeIntervalPartitionPass(*PassRegistry::getPassRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
// run - Calculate the interval partition for this function
|
// 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
|
// IntervalPartition ctor - Build a reduced interval partition from an
|
||||||
// existing interval graph. This takes an additional boolean parameter to
|
// existing interval graph. This takes an additional boolean parameter to
|
||||||
@ -62,7 +62,7 @@ public:
|
|||||||
IntervalPartition(IntervalPartition &I, bool);
|
IntervalPartition(IntervalPartition &I, bool);
|
||||||
|
|
||||||
// print - Show contents in human readable format...
|
// 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
|
// getRootInterval() - Return the root interval that contains the starting
|
||||||
// block of the function.
|
// block of the function.
|
||||||
@ -77,11 +77,11 @@ public:
|
|||||||
// getBlockInterval - Return the interval that a basic block exists in.
|
// getBlockInterval - Return the interval that a basic block exists in.
|
||||||
inline Interval *getBlockInterval(BasicBlock *BB) {
|
inline Interval *getBlockInterval(BasicBlock *BB) {
|
||||||
IntervalMapTy::iterator I = IntervalMap.find(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
|
// getAnalysisUsage - Implement the Pass API
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ public:
|
|||||||
const std::vector<Interval*> &getIntervals() const { return Intervals; }
|
const std::vector<Interval*> &getIntervals() const { return Intervals; }
|
||||||
|
|
||||||
// releaseMemory - Reset state back to before function was analyzed
|
// releaseMemory - Reset state back to before function was analyzed
|
||||||
void releaseMemory();
|
void releaseMemory() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// addIntervalToPartition - Add an interval to the internal list of intervals,
|
// 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
|
/// LazyValueInfo - This pass computes, caches, and vends lazy value constraint
|
||||||
/// information.
|
/// information.
|
||||||
class LazyValueInfo : public FunctionPass {
|
class LazyValueInfo : public FunctionPass {
|
||||||
class DataLayout *TD;
|
const DataLayout *DL;
|
||||||
class TargetLibraryInfo *TLI;
|
class TargetLibraryInfo *TLI;
|
||||||
void *PImpl;
|
void *PImpl;
|
||||||
LazyValueInfo(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
LazyValueInfo(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
||||||
void operator=(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
void operator=(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
LazyValueInfo() : FunctionPass(ID), PImpl(0) {
|
LazyValueInfo() : FunctionPass(ID), PImpl(nullptr) {
|
||||||
initializeLazyValueInfoPass(*PassRegistry::getPassRegistry());
|
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.
|
/// Tristate - This is used to return true/false/dunno results.
|
||||||
enum Tristate {
|
enum Tristate {
|
||||||
@ -69,10 +69,10 @@ public:
|
|||||||
void eraseBlock(BasicBlock *BB);
|
void eraseBlock(BasicBlock *BB);
|
||||||
|
|
||||||
// Implementation boilerplate.
|
// Implementation boilerplate.
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||||
virtual void releaseMemory();
|
void releaseMemory() override;
|
||||||
virtual bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -27,7 +27,7 @@ namespace llvm {
|
|||||||
|
|
||||||
LibCallInfo *LCI;
|
LibCallInfo *LCI;
|
||||||
|
|
||||||
explicit LibCallAliasAnalysis(LibCallInfo *LC = 0)
|
explicit LibCallAliasAnalysis(LibCallInfo *LC = nullptr)
|
||||||
: FunctionPass(ID), LCI(LC) {
|
: FunctionPass(ID), LCI(LC) {
|
||||||
initializeLibCallAliasAnalysisPass(*PassRegistry::getPassRegistry());
|
initializeLibCallAliasAnalysisPass(*PassRegistry::getPassRegistry());
|
||||||
}
|
}
|
||||||
@ -38,17 +38,17 @@ namespace llvm {
|
|||||||
~LibCallAliasAnalysis();
|
~LibCallAliasAnalysis();
|
||||||
|
|
||||||
ModRefResult getModRefInfo(ImmutableCallSite CS,
|
ModRefResult getModRefInfo(ImmutableCallSite CS,
|
||||||
const Location &Loc);
|
const Location &Loc) override;
|
||||||
|
|
||||||
ModRefResult getModRefInfo(ImmutableCallSite CS1,
|
ModRefResult getModRefInfo(ImmutableCallSite CS1,
|
||||||
ImmutableCallSite CS2) {
|
ImmutableCallSite CS2) override {
|
||||||
// TODO: Could compare two direct calls against each other if we cared to.
|
// TODO: Could compare two direct calls against each other if we cared to.
|
||||||
return AliasAnalysis::getModRefInfo(CS1, CS2);
|
return AliasAnalysis::getModRefInfo(CS1, CS2);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||||
|
|
||||||
virtual bool runOnFunction(Function &F) {
|
bool runOnFunction(Function &F) override {
|
||||||
InitializeAliasAnalysis(this); // set up super class
|
InitializeAliasAnalysis(this); // set up super class
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ namespace llvm {
|
|||||||
/// an analysis interface through multiple inheritance. If needed, it
|
/// an analysis interface through multiple inheritance. If needed, it
|
||||||
/// should override this to adjust the this pointer as needed for the
|
/// should override this to adjust the this pointer as needed for the
|
||||||
/// specified pass info.
|
/// specified pass info.
|
||||||
virtual void *getAdjustedAnalysisPointer(const void *PI) {
|
void *getAdjustedAnalysisPointer(const void *PI) override {
|
||||||
if (PI == &AliasAnalysis::ID)
|
if (PI == &AliasAnalysis::ID)
|
||||||
return (AliasAnalysis*)this;
|
return (AliasAnalysis*)this;
|
||||||
return this;
|
return this;
|
||||||
|
@ -27,7 +27,7 @@ namespace llvm {
|
|||||||
/// standard libm functions. The location that they may be interested in is
|
/// standard libm functions. The location that they may be interested in is
|
||||||
/// an abstract location that represents errno for the current target. In
|
/// an abstract location that represents errno for the current target. In
|
||||||
/// this case, a location for errno is anything such that the predicate
|
/// 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()".
|
/// pointer is the result of a call to "__error()".
|
||||||
///
|
///
|
||||||
/// Locations can also be defined in a constant-sensitive way. For example,
|
/// Locations can also be defined in a constant-sensitive way. For example,
|
||||||
@ -130,7 +130,7 @@ namespace llvm {
|
|||||||
mutable const LibCallLocationInfo *Locations;
|
mutable const LibCallLocationInfo *Locations;
|
||||||
mutable unsigned NumLocations;
|
mutable unsigned NumLocations;
|
||||||
public:
|
public:
|
||||||
LibCallInfo() : Impl(0), Locations(0), NumLocations(0) {}
|
LibCallInfo() : Impl(nullptr), Locations(nullptr), NumLocations(0) {}
|
||||||
virtual ~LibCallInfo();
|
virtual ~LibCallInfo();
|
||||||
|
|
||||||
//===------------------------------------------------------------------===//
|
//===------------------------------------------------------------------===//
|
||||||
|
@ -27,7 +27,8 @@ class MDNode;
|
|||||||
/// specified pointer, we do a quick local scan of the basic block containing
|
/// specified pointer, we do a quick local scan of the basic block containing
|
||||||
/// ScanFrom, to determine if the address is already accessed.
|
/// ScanFrom, to determine if the address is already accessed.
|
||||||
bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
|
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
|
/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at
|
||||||
/// the instruction before ScanFrom) checking to see if we have the value 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,
|
Value *FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB,
|
||||||
BasicBlock::iterator &ScanFrom,
|
BasicBlock::iterator &ScanFrom,
|
||||||
unsigned MaxInstsToScan = 6,
|
unsigned MaxInstsToScan = 6,
|
||||||
AliasAnalysis *AA = 0,
|
AliasAnalysis *AA = nullptr,
|
||||||
MDNode **TBAATag = 0);
|
MDNode **TBAATag = nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,10 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/DenseSet.h"
|
#include "llvm/ADT/DenseSet.h"
|
||||||
#include "llvm/ADT/GraphTraits.h"
|
#include "llvm/ADT/GraphTraits.h"
|
||||||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/SmallVector.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 "llvm/Pass.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -53,6 +55,7 @@ class Loop;
|
|||||||
class MDNode;
|
class MDNode;
|
||||||
class PHINode;
|
class PHINode;
|
||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
|
template<class N> class DominatorTreeBase;
|
||||||
template<class N, class M> class LoopInfoBase;
|
template<class N, class M> class LoopInfoBase;
|
||||||
template<class N, class M> class LoopBase;
|
template<class N, class M> class LoopBase;
|
||||||
|
|
||||||
@ -76,7 +79,7 @@ class LoopBase {
|
|||||||
operator=(const LoopBase<BlockT, LoopT> &) LLVM_DELETED_FUNCTION;
|
operator=(const LoopBase<BlockT, LoopT> &) LLVM_DELETED_FUNCTION;
|
||||||
public:
|
public:
|
||||||
/// Loop ctor - This creates an empty loop.
|
/// Loop ctor - This creates an empty loop.
|
||||||
LoopBase() : ParentLoop(0) {}
|
LoopBase() : ParentLoop(nullptr) {}
|
||||||
~LoopBase() {
|
~LoopBase() {
|
||||||
for (size_t i = 0, e = SubLoops.size(); i != e; ++i)
|
for (size_t i = 0, e = SubLoops.size(); i != e; ++i)
|
||||||
delete SubLoops[i];
|
delete SubLoops[i];
|
||||||
@ -103,7 +106,7 @@ public:
|
|||||||
///
|
///
|
||||||
bool contains(const LoopT *L) const {
|
bool contains(const LoopT *L) const {
|
||||||
if (L == this) return true;
|
if (L == this) return true;
|
||||||
if (L == 0) return false;
|
if (!L) return false;
|
||||||
return contains(L->getParentLoop());
|
return contains(L->getParentLoop());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +231,18 @@ public:
|
|||||||
/// A latch block is a block that contains a branch back to the header.
|
/// A latch block is a block that contains a branch back to the header.
|
||||||
BlockT *getLoopLatch() const;
|
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
|
// APIs for updating loop information after changing the CFG
|
||||||
//
|
//
|
||||||
@ -250,7 +265,7 @@ public:
|
|||||||
/// updates the loop depth of the new child.
|
/// updates the loop depth of the new child.
|
||||||
///
|
///
|
||||||
void addChildLoop(LoopT *NewChild) {
|
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);
|
NewChild->ParentLoop = static_cast<LoopT *>(this);
|
||||||
SubLoops.push_back(NewChild);
|
SubLoops.push_back(NewChild);
|
||||||
}
|
}
|
||||||
@ -263,7 +278,7 @@ public:
|
|||||||
LoopT *Child = *I;
|
LoopT *Child = *I;
|
||||||
assert(Child->ParentLoop == this && "Child is not a child of this loop!");
|
assert(Child->ParentLoop == this && "Child is not a child of this loop!");
|
||||||
SubLoops.erase(SubLoops.begin()+(I-begin()));
|
SubLoops.erase(SubLoops.begin()+(I-begin()));
|
||||||
Child->ParentLoop = 0;
|
Child->ParentLoop = nullptr;
|
||||||
return Child;
|
return Child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +333,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class LoopInfoBase<BlockT, LoopT>;
|
friend class LoopInfoBase<BlockT, LoopT>;
|
||||||
explicit LoopBase(BlockT *BB) : ParentLoop(0) {
|
explicit LoopBase(BlockT *BB) : ParentLoop(nullptr) {
|
||||||
Blocks.push_back(BB);
|
Blocks.push_back(BB);
|
||||||
DenseBlockSet.insert(BB);
|
DenseBlockSet.insert(BB);
|
||||||
}
|
}
|
||||||
@ -357,7 +372,7 @@ public:
|
|||||||
/// If null, the terminator of the loop preheader is used.
|
/// If null, the terminator of the loop preheader is used.
|
||||||
///
|
///
|
||||||
bool makeLoopInvariant(Value *V, bool &Changed,
|
bool makeLoopInvariant(Value *V, bool &Changed,
|
||||||
Instruction *InsertPt = 0) const;
|
Instruction *InsertPt = nullptr) const;
|
||||||
|
|
||||||
/// makeLoopInvariant - If the given instruction is inside of the
|
/// makeLoopInvariant - If the given instruction is inside of the
|
||||||
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
|
/// 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.
|
/// If null, the terminator of the loop preheader is used.
|
||||||
///
|
///
|
||||||
bool makeLoopInvariant(Instruction *I, bool &Changed,
|
bool makeLoopInvariant(Instruction *I, bool &Changed,
|
||||||
Instruction *InsertPt = 0) const;
|
Instruction *InsertPt = nullptr) const;
|
||||||
|
|
||||||
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
|
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
|
||||||
/// induction variable: an integer recurrence that starts at 0 and increments
|
/// induction variable: an integer recurrence that starts at 0 and increments
|
||||||
@ -438,6 +453,31 @@ public:
|
|||||||
|
|
||||||
void dump() const;
|
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:
|
private:
|
||||||
friend class LoopInfoBase<BasicBlock, Loop>;
|
friend class LoopInfoBase<BasicBlock, Loop>;
|
||||||
explicit Loop(BasicBlock *BB) : LoopBase<BasicBlock, Loop>(BB) {}
|
explicit Loop(BasicBlock *BB) : LoopBase<BasicBlock, Loop>(BB) {}
|
||||||
@ -516,7 +556,7 @@ public:
|
|||||||
LoopT *removeLoop(iterator I) {
|
LoopT *removeLoop(iterator I) {
|
||||||
assert(I != end() && "Cannot remove end iterator!");
|
assert(I != end() && "Cannot remove end iterator!");
|
||||||
LoopT *L = *I;
|
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()));
|
TopLevelLoops.erase(TopLevelLoops.begin() + (I-begin()));
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
@ -540,14 +580,14 @@ public:
|
|||||||
std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
|
std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
|
||||||
assert(I != TopLevelLoops.end() && "Old loop not at top level!");
|
assert(I != TopLevelLoops.end() && "Old loop not at top level!");
|
||||||
*I = NewLoop;
|
*I = NewLoop;
|
||||||
assert(NewLoop->ParentLoop == 0 && OldLoop->ParentLoop == 0 &&
|
assert(!NewLoop->ParentLoop && !OldLoop->ParentLoop &&
|
||||||
"Loops already embedded into a subloop!");
|
"Loops already embedded into a subloop!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// addTopLevelLoop - This adds the specified loop to the collection of
|
/// addTopLevelLoop - This adds the specified loop to the collection of
|
||||||
/// top-level loops.
|
/// top-level loops.
|
||||||
void addTopLevelLoop(LoopT *New) {
|
void addTopLevelLoop(LoopT *New) {
|
||||||
assert(New->getParentLoop() == 0 && "Loop already in subloop!");
|
assert(!New->getParentLoop() && "Loop already in subloop!");
|
||||||
TopLevelLoops.push_back(New);
|
TopLevelLoops.push_back(New);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,7 +608,7 @@ public:
|
|||||||
|
|
||||||
static bool isNotAlreadyContainedIn(const LoopT *SubLoop,
|
static bool isNotAlreadyContainedIn(const LoopT *SubLoop,
|
||||||
const LoopT *ParentLoop) {
|
const LoopT *ParentLoop) {
|
||||||
if (SubLoop == 0) return true;
|
if (!SubLoop) return true;
|
||||||
if (SubLoop == ParentLoop) return false;
|
if (SubLoop == ParentLoop) return false;
|
||||||
return isNotAlreadyContainedIn(SubLoop->getParentLoop(), ParentLoop);
|
return isNotAlreadyContainedIn(SubLoop->getParentLoop(), ParentLoop);
|
||||||
}
|
}
|
||||||
@ -639,15 +679,15 @@ public:
|
|||||||
|
|
||||||
/// runOnFunction - Calculate the natural loop information.
|
/// 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
|
/// 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
|
/// object. The loop is not deleted, as it will presumably be inserted into
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
#ifndef LLVM_ANALYSIS_LOOPINFOIMPL_H
|
#ifndef LLVM_ANALYSIS_LOOPINFOIMPL_H
|
||||||
#define LLVM_ANALYSIS_LOOPINFOIMPL_H
|
#define LLVM_ANALYSIS_LOOPINFOIMPL_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/DepthFirstIterator.h"
|
||||||
#include "llvm/ADT/PostOrderIterator.h"
|
#include "llvm/ADT/PostOrderIterator.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/Analysis/LoopInfo.h"
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
|
#include "llvm/IR/Dominators.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ BlockT *LoopBase<BlockT, LoopT>::getExitingBlock() const {
|
|||||||
getExitingBlocks(ExitingBlocks);
|
getExitingBlocks(ExitingBlocks);
|
||||||
if (ExitingBlocks.size() == 1)
|
if (ExitingBlocks.size() == 1)
|
||||||
return ExitingBlocks[0];
|
return ExitingBlocks[0];
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getExitBlocks - Return all of the successor blocks of this loop. These
|
/// getExitBlocks - Return all of the successor blocks of this loop. These
|
||||||
@ -78,7 +80,7 @@ BlockT *LoopBase<BlockT, LoopT>::getExitBlock() const {
|
|||||||
getExitBlocks(ExitBlocks);
|
getExitBlocks(ExitBlocks);
|
||||||
if (ExitBlocks.size() == 1)
|
if (ExitBlocks.size() == 1)
|
||||||
return ExitBlocks[0];
|
return ExitBlocks[0];
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
|
/// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
|
||||||
@ -106,14 +108,14 @@ template<class BlockT, class LoopT>
|
|||||||
BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
|
BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
|
||||||
// Keep track of nodes outside the loop branching to the header...
|
// Keep track of nodes outside the loop branching to the header...
|
||||||
BlockT *Out = getLoopPredecessor();
|
BlockT *Out = getLoopPredecessor();
|
||||||
if (!Out) return 0;
|
if (!Out) return nullptr;
|
||||||
|
|
||||||
// Make sure there is only one exit out of the preheader.
|
// Make sure there is only one exit out of the preheader.
|
||||||
typedef GraphTraits<BlockT*> BlockTraits;
|
typedef GraphTraits<BlockT*> BlockTraits;
|
||||||
typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out);
|
typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out);
|
||||||
++SI;
|
++SI;
|
||||||
if (SI != BlockTraits::child_end(Out))
|
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.
|
// The predecessor has exactly one successor, so it is a preheader.
|
||||||
return Out;
|
return Out;
|
||||||
@ -127,7 +129,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
|
|||||||
template<class BlockT, class LoopT>
|
template<class BlockT, class LoopT>
|
||||||
BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
||||||
// Keep track of nodes outside the loop branching to the header...
|
// 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...
|
// Loop over the predecessors of the header node...
|
||||||
BlockT *Header = getHeader();
|
BlockT *Header = getHeader();
|
||||||
@ -138,7 +140,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
|||||||
typename InvBlockTraits::NodeType *N = *PI;
|
typename InvBlockTraits::NodeType *N = *PI;
|
||||||
if (!contains(N)) { // If the block is not in the loop...
|
if (!contains(N)) { // If the block is not in the loop...
|
||||||
if (Out && Out != N)
|
if (Out && Out != N)
|
||||||
return 0; // Multiple predecessors outside the loop
|
return nullptr; // Multiple predecessors outside the loop
|
||||||
Out = N;
|
Out = N;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,11 +160,11 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopLatch() const {
|
|||||||
InvBlockTraits::child_begin(Header);
|
InvBlockTraits::child_begin(Header);
|
||||||
typename InvBlockTraits::ChildIteratorType PE =
|
typename InvBlockTraits::ChildIteratorType PE =
|
||||||
InvBlockTraits::child_end(Header);
|
InvBlockTraits::child_end(Header);
|
||||||
BlockT *Latch = 0;
|
BlockT *Latch = nullptr;
|
||||||
for (; PI != PE; ++PI) {
|
for (; PI != PE; ++PI) {
|
||||||
typename InvBlockTraits::NodeType *N = *PI;
|
typename InvBlockTraits::NodeType *N = *PI;
|
||||||
if (contains(N)) {
|
if (contains(N)) {
|
||||||
if (Latch) return 0;
|
if (Latch) return nullptr;
|
||||||
Latch = N;
|
Latch = N;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,7 +188,7 @@ addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LIB) {
|
|||||||
assert((Blocks.empty() || LIB[getHeader()] == this) &&
|
assert((Blocks.empty() || LIB[getHeader()] == this) &&
|
||||||
"Incorrect LI specified for this loop!");
|
"Incorrect LI specified for this loop!");
|
||||||
assert(NewBB && "Cannot add a null basic block to the 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);
|
LoopT *L = static_cast<LoopT *>(this);
|
||||||
|
|
||||||
@ -208,12 +210,12 @@ template<class BlockT, class LoopT>
|
|||||||
void LoopBase<BlockT, LoopT>::
|
void LoopBase<BlockT, LoopT>::
|
||||||
replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild) {
|
replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild) {
|
||||||
assert(OldChild->ParentLoop == this && "This loop is already broken!");
|
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 =
|
typename std::vector<LoopT *>::iterator I =
|
||||||
std::find(SubLoops.begin(), SubLoops.end(), OldChild);
|
std::find(SubLoops.begin(), SubLoops.end(), OldChild);
|
||||||
assert(I != SubLoops.end() && "OldChild not in loop!");
|
assert(I != SubLoops.end() && "OldChild not in loop!");
|
||||||
*I = NewChild;
|
*I = NewChild;
|
||||||
OldChild->ParentLoop = 0;
|
OldChild->ParentLoop = nullptr;
|
||||||
NewChild->ParentLoop = static_cast<LoopT *>(this);
|
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
|
// though it is permitted if the predecessor is not itself actually
|
||||||
// reachable.
|
// reachable.
|
||||||
BlockT *EntryBB = BB->getParent()->begin();
|
BlockT *EntryBB = BB->getParent()->begin();
|
||||||
for (df_iterator<BlockT *> NI = df_begin(EntryBB),
|
for (BlockT *CB : depth_first(EntryBB))
|
||||||
NE = df_end(EntryBB); NI != NE; ++NI)
|
for (unsigned i = 0, e = OutsideLoopPreds.size(); i != e; ++i)
|
||||||
for (unsigned i = 0, e = OutsideLoopPreds.size(); i != e; ++i)
|
assert(CB != OutsideLoopPreds[i] &&
|
||||||
assert(*NI != OutsideLoopPreds[i] &&
|
"Loop has multiple entry points!");
|
||||||
"Loop has multiple entry points!");
|
|
||||||
}
|
}
|
||||||
assert(HasInsideLoopPreds && "Loop block has no in-loop predecessors!");
|
assert(HasInsideLoopPreds && "Loop block has no in-loop predecessors!");
|
||||||
assert(HasInsideLoopSuccs && "Loop block has no in-loop successors!");
|
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) {
|
for (unsigned i = 0; i < getBlocks().size(); ++i) {
|
||||||
if (i) OS << ",";
|
if (i) OS << ",";
|
||||||
BlockT *BB = getBlocks()[i];
|
BlockT *BB = getBlocks()[i];
|
||||||
WriteAsOperand(OS, BB, false);
|
BB->printAsOperand(OS, false);
|
||||||
if (BB == getHeader()) OS << "<header>";
|
if (BB == getHeader()) OS << "<header>";
|
||||||
if (BB == getLoopLatch()) OS << "<latch>";
|
if (BB == getLoopLatch()) OS << "<latch>";
|
||||||
if (isLoopExiting(BB)) OS << "<exiting>";
|
if (isLoopExiting(BB)) OS << "<exiting>";
|
||||||
|
@ -32,7 +32,8 @@ public:
|
|||||||
|
|
||||||
/// getPrinterPass - Get a pass to print the function corresponding
|
/// getPrinterPass - Get a pass to print the function corresponding
|
||||||
/// to a Loop.
|
/// 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
|
// runOnLoop - This method should be implemented by the subclass to perform
|
||||||
// whatever action is necessary for the specified Loop.
|
// whatever action is necessary for the specified Loop.
|
||||||
@ -56,14 +57,13 @@ public:
|
|||||||
// LPPassManager passes. In such case, pop LPPassManager from the
|
// LPPassManager passes. In such case, pop LPPassManager from the
|
||||||
// stack. This will force assignPassManager() to create new
|
// stack. This will force assignPassManager() to create new
|
||||||
// LPPassManger as expected.
|
// LPPassManger as expected.
|
||||||
void preparePassManager(PMStack &PMS);
|
void preparePassManager(PMStack &PMS) override;
|
||||||
|
|
||||||
/// Assign pass manager to manage this pass
|
/// Assign pass manager to manage this pass
|
||||||
virtual void assignPassManager(PMStack &PMS,
|
void assignPassManager(PMStack &PMS, PassManagerType PMT) override;
|
||||||
PassManagerType PMT);
|
|
||||||
|
|
||||||
/// Return what kind of Pass Manager can manage this pass.
|
/// Return what kind of Pass Manager can manage this pass.
|
||||||
virtual PassManagerType getPotentialPassManagerType() const {
|
PassManagerType getPotentialPassManagerType() const override {
|
||||||
return PMT_LoopPassManager;
|
return PMT_LoopPassManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +81,11 @@ public:
|
|||||||
|
|
||||||
/// deleteAnalysisValue - Delete analysis info associated with value V.
|
/// deleteAnalysisValue - Delete analysis info associated with value V.
|
||||||
virtual void deleteAnalysisValue(Value *V, Loop *L) {}
|
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 {
|
class LPPassManager : public FunctionPass, public PMDataManager {
|
||||||
@ -90,21 +95,21 @@ public:
|
|||||||
|
|
||||||
/// run - Execute all of the passes scheduled for execution. Keep track of
|
/// 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.
|
/// 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.
|
/// Pass Manager itself does not invalidate any analysis info.
|
||||||
// LPPassManager needs LoopInfo.
|
// 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";
|
return "Loop Pass Manager";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual PMDataManager *getAsPMDataManager() { return this; }
|
PMDataManager *getAsPMDataManager() override { return this; }
|
||||||
virtual Pass *getAsPass() { return this; }
|
Pass *getAsPass() override { return this; }
|
||||||
|
|
||||||
/// Print passes managed by this manager
|
/// Print passes managed by this manager
|
||||||
void dumpPassStructure(unsigned Offset);
|
void dumpPassStructure(unsigned Offset) override;
|
||||||
|
|
||||||
LoopPass *getContainedPass(unsigned N) {
|
LoopPass *getContainedPass(unsigned N) {
|
||||||
assert(N < PassVector.size() && "Pass number out of range!");
|
assert(N < PassVector.size() && "Pass number out of range!");
|
||||||
@ -112,7 +117,7 @@ public:
|
|||||||
return LP;
|
return LP;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual PassManagerType getPassManagerType() const {
|
PassManagerType getPassManagerType() const override {
|
||||||
return PMT_LoopPassManager;
|
return PMT_LoopPassManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
#include "llvm/Analysis/TargetFolder.h"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
#include "llvm/IR/IRBuilder.h"
|
||||||
|
#include "llvm/IR/InstVisitor.h"
|
||||||
#include "llvm/IR/Operator.h"
|
#include "llvm/IR/Operator.h"
|
||||||
#include "llvm/InstVisitor.h"
|
#include "llvm/IR/ValueHandle.h"
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
#include "llvm/Support/TargetFolder.h"
|
|
||||||
#include "llvm/Support/ValueHandle.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class CallInst;
|
class CallInst;
|
||||||
@ -190,6 +190,8 @@ public:
|
|||||||
return knownSize(SizeOffset) && knownOffset(SizeOffset);
|
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 visitAllocaInst(AllocaInst &I);
|
||||||
SizeOffsetType visitArgument(Argument &A);
|
SizeOffsetType visitArgument(Argument &A);
|
||||||
SizeOffsetType visitCallSite(CallSite CS);
|
SizeOffsetType visitCallSite(CallSite CS);
|
||||||
@ -231,7 +233,7 @@ class ObjectSizeOffsetEvaluator
|
|||||||
bool RoundToAlign;
|
bool RoundToAlign;
|
||||||
|
|
||||||
SizeOffsetEvalType unknown() {
|
SizeOffsetEvalType unknown() {
|
||||||
return std::make_pair((Value*)0, (Value*)0);
|
return std::make_pair(nullptr, nullptr);
|
||||||
}
|
}
|
||||||
SizeOffsetEvalType compute_(Value *V);
|
SizeOffsetEvalType compute_(Value *V);
|
||||||
|
|
||||||
@ -256,6 +258,7 @@ public:
|
|||||||
return knownSize(SizeOffset) && knownOffset(SizeOffset);
|
return knownSize(SizeOffset) && knownOffset(SizeOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The individual instruction visitors should be treated as private.
|
||||||
SizeOffsetEvalType visitAllocaInst(AllocaInst &I);
|
SizeOffsetEvalType visitAllocaInst(AllocaInst &I);
|
||||||
SizeOffsetEvalType visitCallSite(CallSite CS);
|
SizeOffsetEvalType visitCallSite(CallSite CS);
|
||||||
SizeOffsetEvalType visitExtractElementInst(ExtractElementInst &I);
|
SizeOffsetEvalType visitExtractElementInst(ExtractElementInst &I);
|
||||||
|
@ -15,13 +15,12 @@
|
|||||||
#define LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H
|
#define LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
|
||||||
#include "llvm/ADT/PointerIntPair.h"
|
#include "llvm/ADT/PointerIntPair.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/Analysis/AliasAnalysis.h"
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/IR/BasicBlock.h"
|
#include "llvm/IR/BasicBlock.h"
|
||||||
|
#include "llvm/IR/ValueHandle.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Support/ValueHandle.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class Function;
|
class Function;
|
||||||
@ -98,7 +97,7 @@ namespace llvm {
|
|||||||
PairTy Value;
|
PairTy Value;
|
||||||
explicit MemDepResult(PairTy V) : Value(V) {}
|
explicit MemDepResult(PairTy V) : Value(V) {}
|
||||||
public:
|
public:
|
||||||
MemDepResult() : Value(0, Invalid) {}
|
MemDepResult() : Value(nullptr, Invalid) {}
|
||||||
|
|
||||||
/// get methods: These are static ctor methods for creating various
|
/// get methods: These are static ctor methods for creating various
|
||||||
/// MemDepResult kinds.
|
/// MemDepResult kinds.
|
||||||
@ -156,7 +155,7 @@ namespace llvm {
|
|||||||
/// getInst() - If this is a normal dependency, return the instruction that
|
/// getInst() - If this is a normal dependency, return the instruction that
|
||||||
/// is depended on. Otherwise, return null.
|
/// is depended on. Otherwise, return null.
|
||||||
Instruction *getInst() const {
|
Instruction *getInst() const {
|
||||||
if (Value.getInt() == Other) return NULL;
|
if (Value.getInt() == Other) return nullptr;
|
||||||
return Value.getPointer();
|
return Value.getPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +285,8 @@ namespace llvm {
|
|||||||
/// pointer. May be null if there are no tags or conflicting tags.
|
/// pointer. May be null if there are no tags or conflicting tags.
|
||||||
const MDNode *TBAATag;
|
const MDNode *TBAATag;
|
||||||
|
|
||||||
NonLocalPointerInfo() : Size(AliasAnalysis::UnknownSize), TBAATag(0) {}
|
NonLocalPointerInfo()
|
||||||
|
: Size(AliasAnalysis::UnknownSize), TBAATag(nullptr) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// CachedNonLocalPointerInfo - This map stores the cached results of doing
|
/// CachedNonLocalPointerInfo - This map stores the cached results of doing
|
||||||
@ -323,24 +323,25 @@ namespace llvm {
|
|||||||
|
|
||||||
/// Current AA implementation, just a cache.
|
/// Current AA implementation, just a cache.
|
||||||
AliasAnalysis *AA;
|
AliasAnalysis *AA;
|
||||||
DataLayout *TD;
|
const DataLayout *DL;
|
||||||
DominatorTree *DT;
|
DominatorTree *DT;
|
||||||
OwningPtr<PredIteratorCache> PredCache;
|
std::unique_ptr<PredIteratorCache> PredCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemoryDependenceAnalysis();
|
MemoryDependenceAnalysis();
|
||||||
~MemoryDependenceAnalysis();
|
~MemoryDependenceAnalysis();
|
||||||
static char ID;
|
static char ID;
|
||||||
|
|
||||||
/// Pass Implementation stuff. This doesn't do any analysis eagerly.
|
/// Pass Implementation stuff. This doesn't do any analysis eagerly.
|
||||||
bool runOnFunction(Function &);
|
bool runOnFunction(Function &) override;
|
||||||
|
|
||||||
/// Clean up memory in between runs
|
/// Clean up memory in between runs
|
||||||
void releaseMemory();
|
void releaseMemory() override;
|
||||||
|
|
||||||
/// getAnalysisUsage - Does not modify anything. It uses Value Numbering
|
/// getAnalysisUsage - Does not modify anything. It uses Value Numbering
|
||||||
/// and Alias Analysis.
|
/// and Alias Analysis.
|
||||||
///
|
///
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||||
|
|
||||||
/// getDependency - Return the instruction on which a memory operation
|
/// getDependency - Return the instruction on which a memory operation
|
||||||
/// depends. See the class comment for more details. It is illegal to call
|
/// depends. See the class comment for more details. It is illegal to call
|
||||||
@ -401,7 +402,7 @@ namespace llvm {
|
|||||||
bool isLoad,
|
bool isLoad,
|
||||||
BasicBlock::iterator ScanIt,
|
BasicBlock::iterator ScanIt,
|
||||||
BasicBlock *BB,
|
BasicBlock *BB,
|
||||||
Instruction *QueryInst = 0);
|
Instruction *QueryInst = nullptr);
|
||||||
|
|
||||||
|
|
||||||
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
|
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
|
||||||
@ -415,7 +416,7 @@ namespace llvm {
|
|||||||
int64_t MemLocOffs,
|
int64_t MemLocOffs,
|
||||||
unsigned MemLocSize,
|
unsigned MemLocSize,
|
||||||
const LoadInst *LI,
|
const LoadInst *LI,
|
||||||
const DataLayout &TD);
|
const DataLayout &DL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall,
|
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