Update llvm to release_39 branch r276489, and resolve conflicts.
This commit is contained in:
commit
3ca95b0202
@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2003-2016 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
@ -94,6 +94,8 @@ typedef enum {
|
||||
LLVMJumpTableAttribute = 1ULL << 45,
|
||||
LLVMConvergentAttribute = 1ULL << 46,
|
||||
LLVMSafeStackAttribute = 1ULL << 47,
|
||||
LLVMSwiftSelfAttribute = 1ULL << 48,
|
||||
LLVMSwiftErrorAttribute = 1ULL << 49,
|
||||
*/
|
||||
} LLVMAttribute;
|
||||
|
||||
@ -245,6 +247,38 @@ typedef enum {
|
||||
LLVMX86FastcallCallConv = 65
|
||||
} LLVMCallConv;
|
||||
|
||||
typedef enum {
|
||||
LLVMArgumentValueKind,
|
||||
LLVMBasicBlockValueKind,
|
||||
LLVMMemoryUseValueKind,
|
||||
LLVMMemoryDefValueKind,
|
||||
LLVMMemoryPhiValueKind,
|
||||
|
||||
LLVMFunctionValueKind,
|
||||
LLVMGlobalAliasValueKind,
|
||||
LLVMGlobalIFuncValueKind,
|
||||
LLVMGlobalVariableValueKind,
|
||||
LLVMBlockAddressValueKind,
|
||||
LLVMConstantExprValueKind,
|
||||
LLVMConstantArrayValueKind,
|
||||
LLVMConstantStructValueKind,
|
||||
LLVMConstantVectorValueKind,
|
||||
|
||||
LLVMUndefValueValueKind,
|
||||
LLVMConstantAggregateZeroValueKind,
|
||||
LLVMConstantDataArrayValueKind,
|
||||
LLVMConstantDataVectorValueKind,
|
||||
LLVMConstantIntValueKind,
|
||||
LLVMConstantFPValueKind,
|
||||
LLVMConstantPointerNullValueKind,
|
||||
LLVMConstantTokenNoneValueKind,
|
||||
|
||||
LLVMMetadataAsValueValueKind,
|
||||
LLVMInlineAsmValueKind,
|
||||
|
||||
LLVMInstructionValueKind,
|
||||
} LLVMValueKind;
|
||||
|
||||
typedef enum {
|
||||
LLVMIntEQ = 32, /**< equal */
|
||||
LLVMIntNE, /**< not equal */
|
||||
@ -346,6 +380,20 @@ typedef enum {
|
||||
LLVMDSNote
|
||||
} LLVMDiagnosticSeverity;
|
||||
|
||||
/**
|
||||
* Attribute index are either LLVMAttributeReturnIndex,
|
||||
* LLVMAttributeFunctionIndex or a parameter number from 1 to N.
|
||||
*/
|
||||
enum {
|
||||
LLVMAttributeReturnIndex = 0U,
|
||||
// ISO C restricts enumerator values to range of 'int'
|
||||
// (4294967295 is too large)
|
||||
// LLVMAttributeFunctionIndex = ~0U,
|
||||
LLVMAttributeFunctionIndex = -1,
|
||||
};
|
||||
|
||||
typedef unsigned LLVMAttributeIndex;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -397,6 +445,16 @@ void LLVMContextSetDiagnosticHandler(LLVMContextRef C,
|
||||
LLVMDiagnosticHandler Handler,
|
||||
void *DiagnosticContext);
|
||||
|
||||
/**
|
||||
* Get the diagnostic handler of this context.
|
||||
*/
|
||||
LLVMDiagnosticHandler LLVMContextGetDiagnosticHandler(LLVMContextRef C);
|
||||
|
||||
/**
|
||||
* Get the diagnostic context of this context.
|
||||
*/
|
||||
void *LLVMContextGetDiagnosticContext(LLVMContextRef C);
|
||||
|
||||
/**
|
||||
* Set the yield callback function for this context.
|
||||
*
|
||||
@ -428,9 +486,63 @@ char *LLVMGetDiagInfoDescription(LLVMDiagnosticInfoRef DI);
|
||||
*/
|
||||
LLVMDiagnosticSeverity LLVMGetDiagInfoSeverity(LLVMDiagnosticInfoRef DI);
|
||||
|
||||
unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char* Name,
|
||||
unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char *Name,
|
||||
unsigned SLen);
|
||||
unsigned LLVMGetMDKindID(const char* Name, unsigned SLen);
|
||||
unsigned LLVMGetMDKindID(const char *Name, unsigned SLen);
|
||||
|
||||
/**
|
||||
* Return an unique id given the name of a enum attribute,
|
||||
* or 0 if no attribute by that name exists.
|
||||
*
|
||||
* See http://llvm.org/docs/LangRef.html#parameter-attributes
|
||||
* and http://llvm.org/docs/LangRef.html#function-attributes
|
||||
* for the list of available attributes.
|
||||
*
|
||||
* NB: Attribute names and/or id are subject to change without
|
||||
* going through the C API deprecation cycle.
|
||||
*/
|
||||
unsigned LLVMGetEnumAttributeKindForName(const char *Name, size_t SLen);
|
||||
unsigned LLVMGetLastEnumAttributeKind(void);
|
||||
|
||||
/**
|
||||
* Create an enum attribute.
|
||||
*/
|
||||
LLVMAttributeRef LLVMCreateEnumAttribute(LLVMContextRef C, unsigned KindID,
|
||||
uint64_t Val);
|
||||
|
||||
/**
|
||||
* Get the unique id corresponding to the enum attribute
|
||||
* passed as argument.
|
||||
*/
|
||||
unsigned LLVMGetEnumAttributeKind(LLVMAttributeRef A);
|
||||
|
||||
/**
|
||||
* Get the enum attribute's value. 0 is returned if none exists.
|
||||
*/
|
||||
uint64_t LLVMGetEnumAttributeValue(LLVMAttributeRef A);
|
||||
|
||||
/**
|
||||
* Create a string attribute.
|
||||
*/
|
||||
LLVMAttributeRef LLVMCreateStringAttribute(LLVMContextRef C,
|
||||
const char *K, unsigned KLength,
|
||||
const char *V, unsigned VLength);
|
||||
|
||||
/**
|
||||
* Get the string attribute's kind.
|
||||
*/
|
||||
const char *LLVMGetStringAttributeKind(LLVMAttributeRef A, unsigned *Length);
|
||||
|
||||
/**
|
||||
* Get the string attribute's value.
|
||||
*/
|
||||
const char *LLVMGetStringAttributeValue(LLVMAttributeRef A, unsigned *Length);
|
||||
|
||||
/**
|
||||
* Check for the different types of attributes.
|
||||
*/
|
||||
LLVMBool LLVMIsEnumAttribute(LLVMAttributeRef A);
|
||||
LLVMBool LLVMIsStringAttribute(LLVMAttributeRef A);
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -478,11 +590,36 @@ LLVMModuleRef LLVMCloneModule(LLVMModuleRef M);
|
||||
*/
|
||||
void LLVMDisposeModule(LLVMModuleRef M);
|
||||
|
||||
/**
|
||||
* Obtain the identifier of a module.
|
||||
*
|
||||
* @param M Module to obtain identifier of
|
||||
* @param Len Out parameter which holds the length of the returned string.
|
||||
* @return The identifier of M.
|
||||
* @see Module::getModuleIdentifier()
|
||||
*/
|
||||
const char *LLVMGetModuleIdentifier(LLVMModuleRef M, size_t *Len);
|
||||
|
||||
/**
|
||||
* Set the identifier of a module to a string Ident with length Len.
|
||||
*
|
||||
* @param M The module to set identifier
|
||||
* @param Ident The string to set M's identifier to
|
||||
* @param Len Length of Ident
|
||||
* @see Module::setModuleIdentifier()
|
||||
*/
|
||||
void LLVMSetModuleIdentifier(LLVMModuleRef M, const char *Ident, size_t Len);
|
||||
|
||||
/**
|
||||
* Obtain the data layout for a module.
|
||||
*
|
||||
* @see Module::getDataLayout()
|
||||
* @see Module::getDataLayoutStr()
|
||||
*
|
||||
* LLVMGetDataLayout is DEPRECATED, as the name is not only incorrect,
|
||||
* but match the name of another method on the module. Prefer the use
|
||||
* of LLVMGetDataLayoutStr, which is not ambiguous.
|
||||
*/
|
||||
const char *LLVMGetDataLayoutStr(LLVMModuleRef M);
|
||||
const char *LLVMGetDataLayout(LLVMModuleRef M);
|
||||
|
||||
/**
|
||||
@ -490,7 +627,7 @@ const char *LLVMGetDataLayout(LLVMModuleRef M);
|
||||
*
|
||||
* @see Module::setDataLayout()
|
||||
*/
|
||||
void LLVMSetDataLayout(LLVMModuleRef M, const char *Triple);
|
||||
void LLVMSetDataLayout(LLVMModuleRef M, const char *DataLayoutStr);
|
||||
|
||||
/**
|
||||
* Obtain the target triple for a module.
|
||||
@ -554,7 +691,7 @@ LLVMTypeRef LLVMGetTypeByName(LLVMModuleRef M, const char *Name);
|
||||
*
|
||||
* @see llvm::Module::getNamedMetadata()
|
||||
*/
|
||||
unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char* name);
|
||||
unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char *Name);
|
||||
|
||||
/**
|
||||
* Obtain the named metadata operands for a module.
|
||||
@ -567,7 +704,8 @@ unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char* name);
|
||||
* @see llvm::Module::getNamedMetadata()
|
||||
* @see llvm::MDNode::getOperand()
|
||||
*/
|
||||
void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char* name, LLVMValueRef *Dest);
|
||||
void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char *Name,
|
||||
LLVMValueRef *Dest);
|
||||
|
||||
/**
|
||||
* Add an operand to named metadata.
|
||||
@ -575,7 +713,7 @@ void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char* name, LLVMValueRe
|
||||
* @see llvm::Module::getNamedMetadata()
|
||||
* @see llvm::MDNode::addOperand()
|
||||
*/
|
||||
void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char* name,
|
||||
void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char *Name,
|
||||
LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
@ -1163,6 +1301,13 @@ LLVMTypeRef LLVMX86MMXType(void);
|
||||
*/
|
||||
LLVMTypeRef LLVMTypeOf(LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Obtain the enumerated type of a Value instance.
|
||||
*
|
||||
* @see llvm::Value::getValueID()
|
||||
*/
|
||||
LLVMValueKind LLVMGetValueKind(LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Obtain the string name of a value.
|
||||
*
|
||||
@ -1200,7 +1345,7 @@ char *LLVMPrintValueToString(LLVMValueRef Val);
|
||||
void LLVMReplaceAllUsesWith(LLVMValueRef OldVal, LLVMValueRef NewVal);
|
||||
|
||||
/**
|
||||
* Determine whether the specified constant instance is constant.
|
||||
* Determine whether the specified value instance is constant.
|
||||
*/
|
||||
LLVMBool LLVMIsConstant(LLVMValueRef Val);
|
||||
|
||||
@ -1520,7 +1665,7 @@ LLVMBool LLVMIsConstantString(LLVMValueRef c);
|
||||
*
|
||||
* @see ConstantDataSequential::getAsString()
|
||||
*/
|
||||
const char *LLVMGetAsString(LLVMValueRef c, size_t* out);
|
||||
const char *LLVMGetAsString(LLVMValueRef c, size_t *Length);
|
||||
|
||||
/**
|
||||
* Create an anonymous ConstantStruct with the specified values.
|
||||
@ -1564,7 +1709,7 @@ LLVMValueRef LLVMConstNamedStruct(LLVMTypeRef StructTy,
|
||||
*
|
||||
* @see ConstantDataSequential::getElementAsConstant()
|
||||
*/
|
||||
LLVMValueRef LLVMGetElementAsConstant(LLVMValueRef c, unsigned idx);
|
||||
LLVMValueRef LLVMGetElementAsConstant(LLVMValueRef C, unsigned idx);
|
||||
|
||||
/**
|
||||
* Create a ConstantVector from values.
|
||||
@ -1727,8 +1872,8 @@ unsigned LLVMGetAlignment(LLVMValueRef V);
|
||||
void LLVMSetAlignment(LLVMValueRef V, unsigned Bytes);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCoreValueConstantGlobalVariable Global Variables
|
||||
@ -1798,6 +1943,13 @@ LLVMValueRef LLVMAddAlias(LLVMModuleRef M, LLVMTypeRef Ty, LLVMValueRef Aliasee,
|
||||
*/
|
||||
void LLVMDeleteFunction(LLVMValueRef Fn);
|
||||
|
||||
/**
|
||||
* Check whether the given function has a personality function.
|
||||
*
|
||||
* @see llvm::Function::hasPersonalityFn()
|
||||
*/
|
||||
LLVMBool LLVMHasPersonalityFn(LLVMValueRef Fn);
|
||||
|
||||
/**
|
||||
* Obtain the personality function attached to the function.
|
||||
*
|
||||
@ -1860,6 +2012,19 @@ void LLVMSetGC(LLVMValueRef Fn, const char *Name);
|
||||
*/
|
||||
void LLVMAddFunctionAttr(LLVMValueRef Fn, LLVMAttribute PA);
|
||||
|
||||
void LLVMAddAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
|
||||
LLVMAttributeRef A);
|
||||
LLVMAttributeRef LLVMGetEnumAttributeAtIndex(LLVMValueRef F,
|
||||
LLVMAttributeIndex Idx,
|
||||
unsigned KindID);
|
||||
LLVMAttributeRef LLVMGetStringAttributeAtIndex(LLVMValueRef F,
|
||||
LLVMAttributeIndex Idx,
|
||||
const char *K, unsigned KLen);
|
||||
void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
|
||||
unsigned KindID);
|
||||
void LLVMRemoveStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
|
||||
const char *K, unsigned KLen);
|
||||
|
||||
/**
|
||||
* Add a target-dependent attribute to a function
|
||||
* @see llvm::AttrBuilder::addAttribute()
|
||||
@ -1985,7 +2150,7 @@ LLVMAttribute LLVMGetAttribute(LLVMValueRef Arg);
|
||||
* @see llvm::Argument::addAttr()
|
||||
* @see llvm::AttrBuilder::addAlignmentAttr()
|
||||
*/
|
||||
void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned align);
|
||||
void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned Align);
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -2043,10 +2208,10 @@ LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count);
|
||||
* Obtain the underlying string from a MDString value.
|
||||
*
|
||||
* @param V Instance to obtain string from.
|
||||
* @param Len Memory address which will hold length of returned string.
|
||||
* @param Length Memory address which will hold length of returned string.
|
||||
* @return String data in MDString.
|
||||
*/
|
||||
const char *LLVMGetMDString(LLVMValueRef V, unsigned* Len);
|
||||
const char *LLVMGetMDString(LLVMValueRef V, unsigned *Length);
|
||||
|
||||
/**
|
||||
* Obtain the number of operands from an MDNode value.
|
||||
@ -2105,6 +2270,11 @@ LLVMBool LLVMValueIsBasicBlock(LLVMValueRef Val);
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMValueAsBasicBlock(LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Obtain the string name of a basic block.
|
||||
*/
|
||||
const char *LLVMGetBasicBlockName(LLVMBasicBlockRef BB);
|
||||
|
||||
/**
|
||||
* Obtain the function to which a basic block belongs.
|
||||
*
|
||||
@ -2323,6 +2493,16 @@ LLVMValueRef LLVMGetNextInstruction(LLVMValueRef Inst);
|
||||
*/
|
||||
LLVMValueRef LLVMGetPreviousInstruction(LLVMValueRef Inst);
|
||||
|
||||
/**
|
||||
* Remove and delete an instruction.
|
||||
*
|
||||
* The instruction specified is removed from its containing building
|
||||
* block but is kept alive.
|
||||
*
|
||||
* @see llvm::Instruction::removeFromParent()
|
||||
*/
|
||||
void LLVMInstructionRemoveFromParent(LLVMValueRef Inst);
|
||||
|
||||
/**
|
||||
* Remove and delete an instruction.
|
||||
*
|
||||
@ -2380,6 +2560,17 @@ LLVMValueRef LLVMInstructionClone(LLVMValueRef Inst);
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the argument count for a call instruction.
|
||||
*
|
||||
* This expects an LLVMValueRef that corresponds to a llvm::CallInst or
|
||||
* llvm::InvokeInst.
|
||||
*
|
||||
* @see llvm::CallInst::getNumArgOperands()
|
||||
* @see llvm::InvokeInst::getNumArgOperands()
|
||||
*/
|
||||
unsigned LLVMGetNumArgOperands(LLVMValueRef Instr);
|
||||
|
||||
/**
|
||||
* Set the calling convention for a call instruction.
|
||||
*
|
||||
@ -2401,12 +2592,35 @@ void LLVMSetInstructionCallConv(LLVMValueRef Instr, unsigned CC);
|
||||
*/
|
||||
unsigned LLVMGetInstructionCallConv(LLVMValueRef Instr);
|
||||
|
||||
|
||||
void LLVMAddInstrAttribute(LLVMValueRef Instr, unsigned index, LLVMAttribute);
|
||||
void LLVMRemoveInstrAttribute(LLVMValueRef Instr, unsigned index,
|
||||
LLVMAttribute);
|
||||
void LLVMSetInstrParamAlignment(LLVMValueRef Instr, unsigned index,
|
||||
unsigned align);
|
||||
unsigned Align);
|
||||
|
||||
void LLVMAddCallSiteAttribute(LLVMValueRef C, LLVMAttributeIndex Idx,
|
||||
LLVMAttributeRef A);
|
||||
LLVMAttributeRef LLVMGetCallSiteEnumAttribute(LLVMValueRef C,
|
||||
LLVMAttributeIndex Idx,
|
||||
unsigned KindID);
|
||||
LLVMAttributeRef LLVMGetCallSiteStringAttribute(LLVMValueRef C,
|
||||
LLVMAttributeIndex Idx,
|
||||
const char *K, unsigned KLen);
|
||||
void LLVMRemoveCallSiteEnumAttribute(LLVMValueRef C, LLVMAttributeIndex Idx,
|
||||
unsigned KindID);
|
||||
void LLVMRemoveCallSiteStringAttribute(LLVMValueRef C, LLVMAttributeIndex Idx,
|
||||
const char *K, unsigned KLen);
|
||||
|
||||
/**
|
||||
* Obtain the pointer to the function invoked by this instruction.
|
||||
*
|
||||
* This expects an LLVMValueRef that corresponds to a llvm::CallInst or
|
||||
* llvm::InvokeInst.
|
||||
*
|
||||
* @see llvm::CallInst::getCalledValue()
|
||||
* @see llvm::InvokeInst::getCalledValue()
|
||||
*/
|
||||
LLVMValueRef LLVMGetCalledValue(LLVMValueRef Instr);
|
||||
|
||||
/**
|
||||
* Obtain whether a call instruction is a tail call.
|
||||
@ -2426,6 +2640,42 @@ LLVMBool LLVMIsTailCall(LLVMValueRef CallInst);
|
||||
*/
|
||||
void LLVMSetTailCall(LLVMValueRef CallInst, LLVMBool IsTailCall);
|
||||
|
||||
/**
|
||||
* Return the normal destination basic block.
|
||||
*
|
||||
* This only works on llvm::InvokeInst instructions.
|
||||
*
|
||||
* @see llvm::InvokeInst::getNormalDest()
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMGetNormalDest(LLVMValueRef InvokeInst);
|
||||
|
||||
/**
|
||||
* Return the unwind destination basic block.
|
||||
*
|
||||
* This only works on llvm::InvokeInst instructions.
|
||||
*
|
||||
* @see llvm::InvokeInst::getUnwindDest()
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMGetUnwindDest(LLVMValueRef InvokeInst);
|
||||
|
||||
/**
|
||||
* Set the normal destination basic block.
|
||||
*
|
||||
* This only works on llvm::InvokeInst instructions.
|
||||
*
|
||||
* @see llvm::InvokeInst::setNormalDest()
|
||||
*/
|
||||
void LLVMSetNormalDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B);
|
||||
|
||||
/**
|
||||
* Set the unwind destination basic block.
|
||||
*
|
||||
* This only works on llvm::InvokeInst instructions.
|
||||
*
|
||||
* @see llvm::InvokeInst::setUnwindDest()
|
||||
*/
|
||||
void LLVMSetUnwindDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -2496,6 +2746,47 @@ void LLVMSetCondition(LLVMValueRef Branch, LLVMValueRef Cond);
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMGetSwitchDefaultDest(LLVMValueRef SwitchInstr);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCCoreValueInstructionAlloca Allocas
|
||||
*
|
||||
* Functions in this group only apply to instructions that map to
|
||||
* llvm::AllocaInst instances.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the type that is being allocated by the alloca instruction.
|
||||
*/
|
||||
LLVMTypeRef LLVMGetAllocatedType(LLVMValueRef Alloca);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCCoreValueInstructionGetElementPointer GEPs
|
||||
*
|
||||
* Functions in this group only apply to instructions that map to
|
||||
* llvm::GetElementPtrInst instances.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check whether the given GEP instruction is inbounds.
|
||||
*/
|
||||
LLVMBool LLVMIsInBounds(LLVMValueRef GEP);
|
||||
|
||||
/**
|
||||
* Set the given GEP instruction to be inbounds or not.
|
||||
*/
|
||||
void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool InBounds);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -2530,6 +2821,31 @@ LLVMValueRef LLVMGetIncomingValue(LLVMValueRef PhiNode, unsigned Index);
|
||||
*/
|
||||
LLVMBasicBlockRef LLVMGetIncomingBlock(LLVMValueRef PhiNode, unsigned Index);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCCoreValueInstructionExtractValue ExtractValue
|
||||
* @defgroup LLVMCCoreValueInstructionInsertValue InsertValue
|
||||
*
|
||||
* Functions in this group only apply to instructions that map to
|
||||
* llvm::ExtractValue and llvm::InsertValue instances.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the number of indices.
|
||||
* NB: This also works on GEP.
|
||||
*/
|
||||
unsigned LLVMGetNumIndices(LLVMValueRef Inst);
|
||||
|
||||
/**
|
||||
* Obtain the indices as an array.
|
||||
*/
|
||||
const unsigned *LLVMGetIndices(LLVMValueRef Inst);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -2598,9 +2914,18 @@ void LLVMAddCase(LLVMValueRef Switch, LLVMValueRef OnVal,
|
||||
/* Add a destination to the indirectbr instruction */
|
||||
void LLVMAddDestination(LLVMValueRef IndirectBr, LLVMBasicBlockRef Dest);
|
||||
|
||||
/* Get the number of clauses on the landingpad instruction */
|
||||
unsigned LLVMGetNumClauses(LLVMValueRef LandingPad);
|
||||
|
||||
/* Get the value of the clause at idnex Idx on the landingpad instruction */
|
||||
LLVMValueRef LLVMGetClause(LLVMValueRef LandingPad, unsigned Idx);
|
||||
|
||||
/* Add a catch or filter clause to the landingpad instruction */
|
||||
void LLVMAddClause(LLVMValueRef LandingPad, LLVMValueRef ClauseVal);
|
||||
|
||||
/* Get the 'cleanup' flag in the landingpad instruction */
|
||||
LLVMBool LLVMIsCleanup(LLVMValueRef LandingPad);
|
||||
|
||||
/* Set the 'cleanup' flag in the landingpad instruction */
|
||||
void LLVMSetCleanup(LLVMValueRef LandingPad, LLVMBool Val);
|
||||
|
||||
@ -2780,6 +3105,21 @@ LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, LLVMAtomicRMWBinOp op,
|
||||
LLVMValueRef PTR, LLVMValueRef Val,
|
||||
LLVMAtomicOrdering ordering,
|
||||
LLVMBool singleThread);
|
||||
LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr,
|
||||
LLVMValueRef Cmp, LLVMValueRef New,
|
||||
LLVMAtomicOrdering SuccessOrdering,
|
||||
LLVMAtomicOrdering FailureOrdering,
|
||||
LLVMBool SingleThread);
|
||||
|
||||
LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst);
|
||||
void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread);
|
||||
|
||||
LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst);
|
||||
void LLVMSetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst,
|
||||
LLVMAtomicOrdering Ordering);
|
||||
LLVMAtomicOrdering LLVMGetCmpXchgFailureOrdering(LLVMValueRef CmpXchgInst);
|
||||
void LLVMSetCmpXchgFailureOrdering(LLVMValueRef CmpXchgInst,
|
||||
LLVMAtomicOrdering Ordering);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
@ -16,7 +16,11 @@
|
||||
#define LLVM_C_DISASSEMBLER_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCDisassembler Disassembler
|
||||
@ -251,4 +255,4 @@ size_t LLVMDisasmInstruction(LLVMDisasmContextRef DC, uint8_t *Bytes,
|
||||
}
|
||||
#endif /* !defined(__cplusplus) */
|
||||
|
||||
#endif /* !defined(LLVM_C_DISASSEMBLER_H) */
|
||||
#endif /* LLVM_C_DISASSEMBLER_H */
|
||||
|
@ -14,8 +14,6 @@
|
||||
#ifndef LLVM_C_ERROR_HANDLING_H
|
||||
#define LLVM_C_ERROR_HANDLING_H
|
||||
|
||||
#include "llvm-c/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -27,20 +27,6 @@ typedef enum {
|
||||
should not be used. */
|
||||
} LLVMLinkerMode;
|
||||
|
||||
/* Links the source module into the destination module. The source module is
|
||||
* damaged. The only thing that can be done is destroy it. Optionally returns a
|
||||
* human-readable description of any errors that occurred in linking. OutMessage
|
||||
* must be disposed with LLVMDisposeMessage. The return value is true if an
|
||||
* error occurred, false otherwise.
|
||||
*
|
||||
* Note that the linker mode parameter \p Unused is no longer used, and has
|
||||
* no effect.
|
||||
*
|
||||
* This function is deprecated. Use LLVMLinkModules2 instead.
|
||||
*/
|
||||
LLVMBool LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src,
|
||||
LLVMLinkerMode Unused, char **OutMessage);
|
||||
|
||||
/* Links the source module into the destination module. The source module is
|
||||
* destroyed.
|
||||
* The return value is true if an error occurred, false otherwise.
|
||||
|
@ -23,7 +23,6 @@
|
||||
#define LLVM_C_ORCBINDINGS_H
|
||||
|
||||
#include "llvm-c/Object.h"
|
||||
#include "llvm-c/Support.h"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -33,11 +32,12 @@ extern "C" {
|
||||
typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef;
|
||||
typedef uint32_t LLVMOrcModuleHandle;
|
||||
typedef uint64_t LLVMOrcTargetAddress;
|
||||
typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name,
|
||||
void *LookupCtx);
|
||||
typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx);
|
||||
typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack,
|
||||
void *CallbackCtx);
|
||||
|
||||
typedef enum { LLVMOrcErrSuccess = 0, LLVMOrcErrGeneric } LLVMOrcErrorCode;
|
||||
|
||||
/**
|
||||
* Create an ORC JIT stack.
|
||||
*
|
||||
@ -49,6 +49,14 @@ typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack,
|
||||
*/
|
||||
LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM);
|
||||
|
||||
/**
|
||||
* Get the error message for the most recent error (if any).
|
||||
*
|
||||
* This message is owned by the ORC JIT Stack and will be freed when the stack
|
||||
* is disposed of by LLVMOrcDisposeInstance.
|
||||
*/
|
||||
const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack);
|
||||
|
||||
/**
|
||||
* Mangle the given symbol.
|
||||
* Memory will be allocated for MangledSymbol to hold the result. The client
|
||||
@ -59,7 +67,6 @@ void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol,
|
||||
/**
|
||||
* Dispose of a mangled symbol.
|
||||
*/
|
||||
|
||||
void LLVMOrcDisposeMangledSymbol(char *MangledSymbol);
|
||||
|
||||
/**
|
||||
@ -73,16 +80,16 @@ LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack,
|
||||
/**
|
||||
* Create a named indirect call stub.
|
||||
*/
|
||||
void LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress InitAddr);
|
||||
LLVMOrcErrorCode LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress InitAddr);
|
||||
|
||||
/**
|
||||
* Set the pointer for the given indirect stub.
|
||||
*/
|
||||
void LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress NewAddr);
|
||||
LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
const char *StubName,
|
||||
LLVMOrcTargetAddress NewAddr);
|
||||
|
||||
/**
|
||||
* Add module to be eagerly compiled.
|
||||
@ -103,10 +110,10 @@ LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod,
|
||||
/**
|
||||
* Add an object file.
|
||||
*/
|
||||
LLVMOrcModuleHandle
|
||||
LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, LLVMObjectFileRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
LLVMOrcModuleHandle LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMObjectFileRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Remove a module set from the JIT.
|
||||
|
@ -183,14 +183,27 @@ static inline LLVMBool LLVMInitializeNativeDisassembler(void) {
|
||||
|
||||
/*===-- Target Data -------------------------------------------------------===*/
|
||||
|
||||
/**
|
||||
* Obtain the data layout for a module.
|
||||
*
|
||||
* @see Module::getDataLayout()
|
||||
*/
|
||||
LLVMTargetDataRef LLVMGetModuleDataLayout(LLVMModuleRef M);
|
||||
|
||||
/**
|
||||
* Set the data layout for a module.
|
||||
*
|
||||
* @see Module::setDataLayout()
|
||||
*/
|
||||
void LLVMSetModuleDataLayout(LLVMModuleRef M, LLVMTargetDataRef DL);
|
||||
|
||||
/** Creates target data from a target layout string.
|
||||
See the constructor llvm::DataLayout::DataLayout. */
|
||||
LLVMTargetDataRef LLVMCreateTargetData(const char *StringRep);
|
||||
|
||||
/** Adds target data information to a pass manager. This does not take ownership
|
||||
of the target data.
|
||||
See the method llvm::PassManagerBase::add. */
|
||||
void LLVMAddTargetData(LLVMTargetDataRef TD, LLVMPassManagerRef PM);
|
||||
/** Deallocates a TargetData.
|
||||
See the destructor llvm::DataLayout::~DataLayout. */
|
||||
void LLVMDisposeTargetData(LLVMTargetDataRef TD);
|
||||
|
||||
/** Adds target library information to a pass manager. This does not take
|
||||
ownership of the target library info.
|
||||
@ -275,10 +288,6 @@ unsigned LLVMElementAtOffset(LLVMTargetDataRef TD, LLVMTypeRef StructTy,
|
||||
unsigned long long LLVMOffsetOfElement(LLVMTargetDataRef TD,
|
||||
LLVMTypeRef StructTy, unsigned Element);
|
||||
|
||||
/** Deallocates a TargetData.
|
||||
See the destructor llvm::DataLayout::~DataLayout. */
|
||||
void LLVMDisposeTargetData(LLVMTargetDataRef TD);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -115,8 +115,8 @@ char *LLVMGetTargetMachineCPU(LLVMTargetMachineRef T);
|
||||
LLVMDisposeMessage. */
|
||||
char *LLVMGetTargetMachineFeatureString(LLVMTargetMachineRef T);
|
||||
|
||||
/** Returns the llvm::DataLayout used for this llvm:TargetMachine. */
|
||||
LLVMTargetDataRef LLVMGetTargetMachineData(LLVMTargetMachineRef T);
|
||||
/** Create a DataLayout based on the targetMachine. */
|
||||
LLVMTargetDataRef LLVMCreateTargetDataLayout(LLVMTargetMachineRef T);
|
||||
|
||||
/** Set the target machine's ASM verbosity. */
|
||||
void LLVMSetTargetMachineAsmVerbosity(LLVMTargetMachineRef T,
|
||||
|
@ -104,13 +104,13 @@ void LLVMAddReassociatePass(LLVMPassManagerRef PM);
|
||||
/** See llvm::createSCCPPass function. */
|
||||
void LLVMAddSCCPPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createScalarReplAggregatesPass function. */
|
||||
/** See llvm::createSROAPass function. */
|
||||
void LLVMAddScalarReplAggregatesPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createScalarReplAggregatesPass function. */
|
||||
/** See llvm::createSROAPass function. */
|
||||
void LLVMAddScalarReplAggregatesPassSSA(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createScalarReplAggregatesPass function. */
|
||||
/** See llvm::createSROAPass function. */
|
||||
void LLVMAddScalarReplAggregatesPassWithThreshold(LLVMPassManagerRef PM,
|
||||
int Threshold);
|
||||
|
||||
|
@ -108,6 +108,13 @@ typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef;
|
||||
* @see llvm::Use */
|
||||
typedef struct LLVMOpaqueUse *LLVMUseRef;
|
||||
|
||||
/**
|
||||
* Used to represent an attributes.
|
||||
*
|
||||
* @see llvm::Attribute
|
||||
*/
|
||||
typedef struct LLVMOpaqueAttributeRef *LLVMAttributeRef;
|
||||
|
||||
/**
|
||||
* @see llvm::DiagnosticInfo
|
||||
*/
|
||||
|
@ -16,7 +16,11 @@
|
||||
#ifndef LLVM_C_LTO_H
|
||||
#define LLVM_C_LTO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
@ -40,7 +44,7 @@ typedef bool lto_bool_t;
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define LTO_API_VERSION 17
|
||||
#define LTO_API_VERSION 20
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
@ -91,6 +95,9 @@ typedef struct LLVMOpaqueLTOModule *lto_module_t;
|
||||
/** opaque reference to a code generator */
|
||||
typedef struct LLVMOpaqueLTOCodeGenerator *lto_code_gen_t;
|
||||
|
||||
/** opaque reference to a thin code generator */
|
||||
typedef struct LLVMOpaqueThinLTOCodeGenerator *thinlto_code_gen_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -103,7 +110,6 @@ extern "C" {
|
||||
extern const char*
|
||||
lto_get_version(void);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the last error string or NULL if last operation was successful.
|
||||
*
|
||||
@ -120,7 +126,6 @@ lto_get_error_message(void);
|
||||
extern lto_bool_t
|
||||
lto_module_is_object_file(const char* path);
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a file is a loadable object compiled for requested target.
|
||||
*
|
||||
@ -130,15 +135,22 @@ extern lto_bool_t
|
||||
lto_module_is_object_file_for_target(const char* path,
|
||||
const char* target_triple_prefix);
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a buffer is a loadable object file.
|
||||
* Return true if \p Buffer contains a bitcode file with ObjC code (category
|
||||
* or class) in it.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
* \since LTO_API_VERSION=20
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_module_is_object_file_in_memory(const void* mem, size_t length);
|
||||
lto_module_has_objc_category(const void *mem, size_t length);
|
||||
|
||||
/**
|
||||
* Checks if a buffer is a loadable object file.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
*/
|
||||
extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem,
|
||||
size_t length);
|
||||
|
||||
/**
|
||||
* Checks if a buffer is a loadable object compiled for requested target.
|
||||
@ -149,7 +161,6 @@ extern lto_bool_t
|
||||
lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length,
|
||||
const char* target_triple_prefix);
|
||||
|
||||
|
||||
/**
|
||||
* Loads an object file from disk.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
@ -159,7 +170,6 @@ lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length,
|
||||
extern lto_module_t
|
||||
lto_module_create(const char* path);
|
||||
|
||||
|
||||
/**
|
||||
* Loads an object file from memory.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
@ -252,7 +262,6 @@ lto_module_get_target_triple(lto_module_t mod);
|
||||
extern void
|
||||
lto_module_set_target_triple(lto_module_t mod, const char *triple);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of symbols in the object module.
|
||||
*
|
||||
@ -261,7 +270,6 @@ lto_module_set_target_triple(lto_module_t mod, const char *triple);
|
||||
extern unsigned int
|
||||
lto_module_get_num_symbols(lto_module_t mod);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the ith symbol in the object module.
|
||||
*
|
||||
@ -270,7 +278,6 @@ lto_module_get_num_symbols(lto_module_t mod);
|
||||
extern const char*
|
||||
lto_module_get_symbol_name(lto_module_t mod, unsigned int index);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the attributes of the ith symbol in the object module.
|
||||
*
|
||||
@ -279,7 +286,6 @@ lto_module_get_symbol_name(lto_module_t mod, unsigned int index);
|
||||
extern lto_symbol_attributes
|
||||
lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the module's linker options.
|
||||
*
|
||||
@ -291,7 +297,6 @@ lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index);
|
||||
extern const char*
|
||||
lto_module_get_linkeropts(lto_module_t mod);
|
||||
|
||||
|
||||
/**
|
||||
* Diagnostic severity.
|
||||
*
|
||||
@ -393,7 +398,6 @@ lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod);
|
||||
extern lto_bool_t
|
||||
lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model);
|
||||
|
||||
|
||||
/**
|
||||
* Sets which PIC code model to generated.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
@ -403,7 +407,6 @@ lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model);
|
||||
extern lto_bool_t
|
||||
lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the cpu to generate code for.
|
||||
*
|
||||
@ -412,7 +415,6 @@ lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model);
|
||||
extern void
|
||||
lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the location of the assembler tool to run. If not set, libLTO
|
||||
* will use gcc to invoke the assembler.
|
||||
@ -548,6 +550,242 @@ extern void
|
||||
lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
|
||||
lto_bool_t ShouldEmbedUselists);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @defgroup LLVMCTLTO ThinLTO
|
||||
* @ingroup LLVMC
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Type to wrap a single object returned by ThinLTO.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
typedef struct {
|
||||
const char *Buffer;
|
||||
size_t Size;
|
||||
} LTOObjectBuffer;
|
||||
|
||||
/**
|
||||
* Instantiates a ThinLTO code generator.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
*
|
||||
* The ThinLTOCodeGenerator is not intended to be reuse for multiple
|
||||
* compilation: the model is that the client adds modules to the generator and
|
||||
* ask to perform the ThinLTO optimizations / codegen, and finally destroys the
|
||||
* codegenerator.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern thinlto_code_gen_t thinlto_create_codegen(void);
|
||||
|
||||
/**
|
||||
* Frees the generator and all memory it internally allocated.
|
||||
* Upon return the thinlto_code_gen_t is no longer valid.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_dispose(thinlto_code_gen_t cg);
|
||||
|
||||
/**
|
||||
* Add a module to a ThinLTO code generator. Identifier has to be unique among
|
||||
* all the modules in a code generator. The data buffer stays owned by the
|
||||
* client, and is expected to be available for the entire lifetime of the
|
||||
* thinlto_code_gen_t it is added to.
|
||||
*
|
||||
* On failure, returns NULL (check lto_get_error_message() for details).
|
||||
*
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_add_module(thinlto_code_gen_t cg,
|
||||
const char *identifier, const char *data,
|
||||
int length);
|
||||
|
||||
/**
|
||||
* Optimize and codegen all the modules added to the codegenerator using
|
||||
* ThinLTO. Resulting objects are accessible using thinlto_module_get_object().
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_process(thinlto_code_gen_t cg);
|
||||
|
||||
/**
|
||||
* Returns the number of object files produced by the ThinLTO CodeGenerator.
|
||||
*
|
||||
* It usually matches the number of input files, but this is not a guarantee of
|
||||
* the API and may change in future implementation, so the client should not
|
||||
* assume it.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern unsigned int thinlto_module_get_num_objects(thinlto_code_gen_t cg);
|
||||
|
||||
/**
|
||||
* Returns a reference to the ith object file produced by the ThinLTO
|
||||
* CodeGenerator.
|
||||
*
|
||||
* Client should use \p thinlto_module_get_num_objects() to get the number of
|
||||
* available objects.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg,
|
||||
unsigned int index);
|
||||
|
||||
/**
|
||||
* Sets which PIC code model to generate.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg,
|
||||
lto_codegen_model);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control
|
||||
* @ingroup LLVMCTLTO
|
||||
*
|
||||
* These entry points control the ThinLTO cache. The cache is intended to
|
||||
* support incremental build, and thus needs to be persistent accross build.
|
||||
* The client enabled the cache by supplying a path to an existing directory.
|
||||
* The code generator will use this to store objects files that may be reused
|
||||
* during a subsequent build.
|
||||
* To avoid filling the disk space, a few knobs are provided:
|
||||
* - The pruning interval limit the frequency at which the garbage collector
|
||||
* will try to scan the cache directory to prune it from expired entries.
|
||||
* Setting to -1 disable the pruning (default).
|
||||
* - The pruning expiration time indicates to the garbage collector how old an
|
||||
* entry needs to be to be removed.
|
||||
* - Finally, the garbage collector can be instructed to prune the cache till
|
||||
* the occupied space goes below a threshold.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the path to a directory to use as a cache storage for incremental build.
|
||||
* Setting this activates caching.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg,
|
||||
const char *cache_dir);
|
||||
|
||||
/**
|
||||
* Sets the cache pruning interval (in seconds). A negative value disable the
|
||||
* pruning. An unspecified default value will be applied, and a value of 0 will
|
||||
* be ignored.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg,
|
||||
int interval);
|
||||
|
||||
/**
|
||||
* Sets the maximum cache size that can be persistent across build, in terms of
|
||||
* percentage of the available space on the the disk. Set to 100 to indicate
|
||||
* no limit, 50 to indicate that the cache size will not be left over half the
|
||||
* available space. A value over 100 will be reduced to 100, a value of 0 will
|
||||
* be ignored. An unspecified default value will be applied.
|
||||
*
|
||||
* The formula looks like:
|
||||
* AvailableSpace = FreeSpace + ExistingCacheSize
|
||||
* NewCacheSize = AvailableSpace * P/100
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_final_cache_size_relative_to_available_space(
|
||||
thinlto_code_gen_t cg, unsigned percentage);
|
||||
|
||||
/**
|
||||
* Sets the expiration (in seconds) for an entry in the cache. An unspecified
|
||||
* default value will be applied. A value of 0 will be ignored.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
|
||||
unsigned expiration);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the path to a directory to use as a storage for temporary bitcode files.
|
||||
* The intention is to make the bitcode files available for debugging at various
|
||||
* stage of the pipeline.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg,
|
||||
const char *save_temps_dir);
|
||||
|
||||
/**
|
||||
* Sets the cpu to generate code for.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cpu(thinlto_code_gen_t cg, const char *cpu);
|
||||
|
||||
/**
|
||||
* Disable CodeGen, only run the stages till codegen and stop. The output will
|
||||
* be bitcode.
|
||||
*
|
||||
* \since LTO_API_VERSION=19
|
||||
*/
|
||||
extern void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg,
|
||||
lto_bool_t disable);
|
||||
|
||||
/**
|
||||
* Perform CodeGen only: disable all other stages.
|
||||
*
|
||||
* \since LTO_API_VERSION=19
|
||||
*/
|
||||
extern void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg,
|
||||
lto_bool_t codegen_only);
|
||||
|
||||
/**
|
||||
* Parse -mllvm style debug options.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_debug_options(const char *const *options, int number);
|
||||
|
||||
/**
|
||||
* Test if a module has support for ThinLTO linking.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern lto_bool_t lto_module_is_thinlto(lto_module_t mod);
|
||||
|
||||
/**
|
||||
* Adds a symbol to the list of global symbols that must exist in the final
|
||||
* generated code. If a function is not listed there, it might be inlined into
|
||||
* every usage and optimized away. For every single module, the functions
|
||||
* referenced from code outside of the ThinLTO modules need to be added here.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_add_must_preserve_symbol(thinlto_code_gen_t cg,
|
||||
const char *name,
|
||||
int length);
|
||||
|
||||
/**
|
||||
* Adds a symbol to the list of global symbols that are cross-referenced between
|
||||
* ThinLTO files. If the ThinLTO CodeGenerator can ensure that every
|
||||
* references from a ThinLTO module to this symbol is optimized away, then
|
||||
* the symbol can be discarded.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg,
|
||||
const char *name,
|
||||
int length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -556,4 +794,4 @@ lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
#endif /* LLVM_C_LTO_H */
|
||||
|
@ -25,6 +25,8 @@ struct fltSemantics;
|
||||
class APSInt;
|
||||
class StringRef;
|
||||
|
||||
template <typename T> class SmallVectorImpl;
|
||||
|
||||
/// Enum that represents what fraction of the LSB truncated bits of an fp number
|
||||
/// represent.
|
||||
///
|
||||
@ -511,19 +513,12 @@ public:
|
||||
/// 0 -> \c IEK_Zero
|
||||
/// Inf -> \c IEK_Inf
|
||||
///
|
||||
friend int ilogb(const APFloat &Arg) {
|
||||
if (Arg.isNaN())
|
||||
return IEK_NaN;
|
||||
if (Arg.isZero())
|
||||
return IEK_Zero;
|
||||
if (Arg.isInfinity())
|
||||
return IEK_Inf;
|
||||
|
||||
return Arg.exponent;
|
||||
}
|
||||
friend int ilogb(const APFloat &Arg);
|
||||
|
||||
/// \brief Returns: X * 2^Exp for integral exponents.
|
||||
friend APFloat scalbn(APFloat X, int Exp);
|
||||
friend APFloat scalbn(APFloat X, int Exp, roundingMode);
|
||||
|
||||
friend APFloat frexp(const APFloat &X, int &Exp, roundingMode);
|
||||
|
||||
private:
|
||||
|
||||
@ -579,6 +574,7 @@ private:
|
||||
const APInt *fill);
|
||||
void makeInf(bool Neg = false);
|
||||
void makeZero(bool Neg = false);
|
||||
void makeQuiet();
|
||||
|
||||
/// @}
|
||||
|
||||
@ -651,7 +647,14 @@ private:
|
||||
/// These additional declarations are required in order to compile LLVM with IBM
|
||||
/// xlC compiler.
|
||||
hash_code hash_value(const APFloat &Arg);
|
||||
APFloat scalbn(APFloat X, int Exp);
|
||||
int ilogb(const APFloat &Arg);
|
||||
APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode);
|
||||
|
||||
/// \brief Equivalent of C standard library function.
|
||||
///
|
||||
/// While the C standard says Exp is an unspecified value for infinity and nan,
|
||||
/// this returns INT_MAX for infinities, and INT_MIN for NaNs.
|
||||
APFloat frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM);
|
||||
|
||||
/// \brief Returns the absolute value of the argument.
|
||||
inline APFloat abs(APFloat X) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
#ifndef LLVM_ADT_APINT_H
|
||||
#define LLVM_ADT_APINT_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cassert>
|
||||
@ -31,6 +30,7 @@ class hash_code;
|
||||
class raw_ostream;
|
||||
|
||||
template <typename T> class SmallVectorImpl;
|
||||
template <typename T> class ArrayRef;
|
||||
|
||||
// An unsigned host type used as a single part of a multi-part
|
||||
// bignum.
|
||||
@ -177,11 +177,11 @@ class APInt {
|
||||
/// provides a more convenient form of divide for internal use since KnuthDiv
|
||||
/// has specific constraints on its inputs. If those constraints are not met
|
||||
/// then it provides a simpler form of divide.
|
||||
static void divide(const APInt LHS, unsigned lhsWords, const APInt &RHS,
|
||||
static void divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
||||
unsigned rhsWords, APInt *Quotient, APInt *Remainder);
|
||||
|
||||
/// out-of-line slow case for inline constructor
|
||||
void initSlowCase(unsigned numBits, uint64_t val, bool isSigned);
|
||||
void initSlowCase(uint64_t val, bool isSigned);
|
||||
|
||||
/// shared code between two array constructors
|
||||
void initFromArray(ArrayRef<uint64_t> array);
|
||||
@ -239,7 +239,7 @@ public:
|
||||
if (isSingleWord())
|
||||
VAL = val;
|
||||
else
|
||||
initSlowCase(numBits, val, isSigned);
|
||||
initSlowCase(val, isSigned);
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
||||
@ -625,7 +625,12 @@ public:
|
||||
/// Negates *this using two's complement logic.
|
||||
///
|
||||
/// \returns An APInt value representing the negation of *this.
|
||||
APInt operator-() const { return APInt(BitWidth, 0) - (*this); }
|
||||
APInt operator-() const {
|
||||
APInt Result(*this);
|
||||
Result.flipAllBits();
|
||||
++Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// \brief Logical negation operator.
|
||||
///
|
||||
@ -835,13 +840,13 @@ public:
|
||||
///
|
||||
/// Adds RHS to this APInt and returns the result.
|
||||
APInt operator+(const APInt &RHS) const;
|
||||
APInt operator+(uint64_t RHS) const { return (*this) + APInt(BitWidth, RHS); }
|
||||
APInt operator+(uint64_t RHS) const;
|
||||
|
||||
/// \brief Subtraction operator.
|
||||
///
|
||||
/// Subtracts RHS from this APInt and returns the result.
|
||||
APInt operator-(const APInt &RHS) const;
|
||||
APInt operator-(uint64_t RHS) const { return (*this) - APInt(BitWidth, RHS); }
|
||||
APInt operator-(uint64_t RHS) const;
|
||||
|
||||
/// \brief Left logical shift operator.
|
||||
///
|
||||
@ -1451,6 +1456,10 @@ public:
|
||||
/// \returns a byte-swapped representation of this APInt Value.
|
||||
APInt LLVM_ATTRIBUTE_UNUSED_RESULT byteSwap() const;
|
||||
|
||||
/// \returns the value with the bit representation reversed of this APInt
|
||||
/// Value.
|
||||
APInt LLVM_ATTRIBUTE_UNUSED_RESULT reverseBits() const;
|
||||
|
||||
/// \brief Converts this APInt to a double value.
|
||||
double roundToDouble(bool isSigned) const;
|
||||
|
||||
@ -1744,16 +1753,24 @@ inline raw_ostream &operator<<(raw_ostream &OS, const APInt &I) {
|
||||
namespace APIntOps {
|
||||
|
||||
/// \brief Determine the smaller of two APInts considered to be signed.
|
||||
inline APInt smin(const APInt &A, const APInt &B) { return A.slt(B) ? A : B; }
|
||||
inline const APInt &smin(const APInt &A, const APInt &B) {
|
||||
return A.slt(B) ? A : B;
|
||||
}
|
||||
|
||||
/// \brief Determine the larger of two APInts considered to be signed.
|
||||
inline APInt smax(const APInt &A, const APInt &B) { return A.sgt(B) ? A : B; }
|
||||
inline const APInt &smax(const APInt &A, const APInt &B) {
|
||||
return A.sgt(B) ? A : B;
|
||||
}
|
||||
|
||||
/// \brief Determine the smaller of two APInts considered to be signed.
|
||||
inline APInt umin(const APInt &A, const APInt &B) { return A.ult(B) ? A : B; }
|
||||
inline const APInt &umin(const APInt &A, const APInt &B) {
|
||||
return A.ult(B) ? A : B;
|
||||
}
|
||||
|
||||
/// \brief Determine the larger of two APInts considered to be unsigned.
|
||||
inline APInt umax(const APInt &A, const APInt &B) { return A.ugt(B) ? A : B; }
|
||||
inline const APInt &umax(const APInt &A, const APInt &B) {
|
||||
return A.ugt(B) ? A : B;
|
||||
}
|
||||
|
||||
/// \brief Check if the specified APInt has a N-bits unsigned integer value.
|
||||
inline bool isIntN(unsigned N, const APInt &APIVal) { return APIVal.isIntN(N); }
|
||||
@ -1770,6 +1787,13 @@ inline bool isMask(unsigned numBits, const APInt &APIVal) {
|
||||
APIVal == APInt::getLowBitsSet(APIVal.getBitWidth(), numBits);
|
||||
}
|
||||
|
||||
/// \returns true if the argument is a non-empty sequence of ones starting at
|
||||
/// the least significant bit with the remainder zero (32 bit version).
|
||||
/// Ex. isMask(0x0000FFFFU) == true.
|
||||
inline bool isMask(const APInt &Value) {
|
||||
return (Value != 0) && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// \brief Return true if the argument APInt value contains a sequence of ones
|
||||
/// with the remainder zero.
|
||||
inline bool isShiftedMask(unsigned numBits, const APInt &APIVal) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// ArrayRef - Represent a constant reference to an array (0 or more elements
|
||||
/// consecutively in memory), i.e. a start pointer and a length. It allows
|
||||
/// various APIs to take consecutive elements easily and conveniently.
|
||||
@ -92,19 +91,20 @@ namespace llvm {
|
||||
/// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
|
||||
/// ensure that only ArrayRefs of pointers can be converted.
|
||||
template <typename U>
|
||||
ArrayRef(const ArrayRef<U *> &A,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type* = 0)
|
||||
ArrayRef(
|
||||
const ArrayRef<U *> &A,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type * = nullptr)
|
||||
: Data(A.data()), Length(A.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
|
||||
/// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
|
||||
/// whenever we copy-construct an ArrayRef.
|
||||
template<typename U, typename DummyT>
|
||||
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<U*, DummyT> &Vec,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *,
|
||||
T const *>::value>::type* = 0)
|
||||
/*implicit*/ ArrayRef(
|
||||
const SmallVectorTemplateCommon<U *, DummyT> &Vec,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type * = nullptr)
|
||||
: Data(Vec.data()), Length(Vec.size()) {
|
||||
}
|
||||
|
||||
@ -161,20 +161,26 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
ArrayRef<T> slice(unsigned N) const {
|
||||
ArrayRef<T> slice(size_t N) const {
|
||||
assert(N <= size() && "Invalid specifier");
|
||||
return ArrayRef<T>(data()+N, size()-N);
|
||||
}
|
||||
|
||||
/// slice(n, m) - Chop off the first N elements of the array, and keep M
|
||||
/// elements in the array.
|
||||
ArrayRef<T> slice(unsigned N, unsigned M) const {
|
||||
ArrayRef<T> slice(size_t N, size_t M) const {
|
||||
assert(N+M <= size() && "Invalid specifier");
|
||||
return ArrayRef<T>(data()+N, M);
|
||||
}
|
||||
|
||||
// \brief Drop the last \p N elements of the array.
|
||||
ArrayRef<T> drop_back(unsigned N = 1) const {
|
||||
/// \brief Drop the first \p N elements of the array.
|
||||
ArrayRef<T> drop_front(size_t N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return slice(N, size() - N);
|
||||
}
|
||||
|
||||
/// \brief Drop the last \p N elements of the array.
|
||||
ArrayRef<T> drop_back(size_t N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return slice(0, size() - N);
|
||||
}
|
||||
@ -273,19 +279,25 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
MutableArrayRef<T> slice(unsigned N) const {
|
||||
MutableArrayRef<T> slice(size_t N) const {
|
||||
assert(N <= this->size() && "Invalid specifier");
|
||||
return MutableArrayRef<T>(data()+N, this->size()-N);
|
||||
}
|
||||
|
||||
/// slice(n, m) - Chop off the first N elements of the array, and keep M
|
||||
/// elements in the array.
|
||||
MutableArrayRef<T> slice(unsigned N, unsigned M) const {
|
||||
MutableArrayRef<T> slice(size_t N, size_t M) const {
|
||||
assert(N+M <= this->size() && "Invalid specifier");
|
||||
return MutableArrayRef<T>(data()+N, M);
|
||||
}
|
||||
|
||||
MutableArrayRef<T> drop_back(unsigned N) const {
|
||||
/// \brief Drop the first \p N elements of the array.
|
||||
MutableArrayRef<T> drop_front(size_t N = 1) const {
|
||||
assert(this->size() >= N && "Dropping more elements than exist");
|
||||
return slice(N, this->size() - N);
|
||||
}
|
||||
|
||||
MutableArrayRef<T> drop_back(size_t N = 1) const {
|
||||
assert(this->size() >= N && "Dropping more elements than exist");
|
||||
return slice(0, this->size() - N);
|
||||
}
|
||||
@ -379,6 +391,6 @@ namespace llvm {
|
||||
template <typename T> hash_code hash_value(ArrayRef<T> S) {
|
||||
return hash_combine_range(S.begin(), S.end());
|
||||
}
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_ARRAYREF_H
|
||||
|
@ -14,13 +14,13 @@
|
||||
#ifndef LLVM_ADT_BITVECTOR_H
|
||||
#define LLVM_ADT_BITVECTOR_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -69,7 +69,7 @@ public:
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return ((*WordRef) & (BitWord(1) << BitPos)) ? true : false;
|
||||
return ((*WordRef) & (BitWord(1) << BitPos)) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -105,6 +105,7 @@ public:
|
||||
BitVector(BitVector &&RHS)
|
||||
: Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
|
||||
RHS.Bits = nullptr;
|
||||
RHS.Size = RHS.Capacity = 0;
|
||||
}
|
||||
|
||||
~BitVector() {
|
||||
@ -244,7 +245,7 @@ public:
|
||||
|
||||
BitWord PrefixMask = ~0UL << (I % BITWORD_SIZE);
|
||||
Bits[I / BITWORD_SIZE] |= PrefixMask;
|
||||
I = RoundUpToAlignment(I, BITWORD_SIZE);
|
||||
I = alignTo(I, BITWORD_SIZE);
|
||||
|
||||
for (; I + BITWORD_SIZE <= E; I += BITWORD_SIZE)
|
||||
Bits[I / BITWORD_SIZE] = ~0UL;
|
||||
@ -283,7 +284,7 @@ public:
|
||||
|
||||
BitWord PrefixMask = ~0UL << (I % BITWORD_SIZE);
|
||||
Bits[I / BITWORD_SIZE] &= ~PrefixMask;
|
||||
I = RoundUpToAlignment(I, BITWORD_SIZE);
|
||||
I = alignTo(I, BITWORD_SIZE);
|
||||
|
||||
for (; I + BITWORD_SIZE <= E; I += BITWORD_SIZE)
|
||||
Bits[I / BITWORD_SIZE] = 0UL;
|
||||
@ -454,6 +455,7 @@ public:
|
||||
Capacity = RHS.Capacity;
|
||||
|
||||
RHS.Bits = nullptr;
|
||||
RHS.Size = RHS.Capacity = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -576,7 +578,7 @@ static inline size_t capacity_in_bytes(const BitVector &X) {
|
||||
return X.getMemorySize();
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
namespace std {
|
||||
/// Implement std::swap in terms of BitVector swap.
|
||||
@ -584,6 +586,6 @@ namespace std {
|
||||
swap(llvm::BitVector &LHS, llvm::BitVector &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
}
|
||||
} // end namespace std
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_BITVECTOR_H
|
||||
|
153
contrib/llvm/include/llvm/ADT/BitmaskEnum.h
Normal file
153
contrib/llvm/include/llvm/ADT/BitmaskEnum.h
Normal file
@ -0,0 +1,153 @@
|
||||
//===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_BITMASKENUM_H
|
||||
#define LLVM_ADT_BITMASKENUM_H
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
/// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can
|
||||
/// perform bitwise operations on it without putting static_cast everywhere.
|
||||
///
|
||||
/// \code
|
||||
/// enum MyEnum {
|
||||
/// E1 = 1, E2 = 2, E3 = 4, E4 = 8,
|
||||
/// LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
|
||||
/// };
|
||||
///
|
||||
/// void Foo() {
|
||||
/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Normally when you do a bitwise operation on an enum value, you get back an
|
||||
/// instance of the underlying type (e.g. int). But using this macro, bitwise
|
||||
/// ops on your enum will return you back instances of the enum. This is
|
||||
/// particularly useful for enums which represent a combination of flags.
|
||||
///
|
||||
/// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual
|
||||
/// value in your enum.
|
||||
///
|
||||
/// All of the enum's values must be non-negative.
|
||||
#define LLVM_MARK_AS_BITMASK_ENUM(LargestValue) \
|
||||
LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue
|
||||
|
||||
/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used
|
||||
/// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace.
|
||||
///
|
||||
/// Suppose you have an enum foo::bar::MyEnum. Before using
|
||||
/// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put
|
||||
/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or
|
||||
/// namespace foo::bar. This allows the relevant operator overloads to be found
|
||||
/// by ADL.
|
||||
///
|
||||
/// You don't need to use this macro in namespace llvm; it's done at the bottom
|
||||
/// of this file.
|
||||
#define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \
|
||||
using ::llvm::BitmaskEnumDetail::operator~; \
|
||||
using ::llvm::BitmaskEnumDetail::operator|; \
|
||||
using ::llvm::BitmaskEnumDetail::operator&; \
|
||||
using ::llvm::BitmaskEnumDetail::operator^; \
|
||||
using ::llvm::BitmaskEnumDetail::operator|=; \
|
||||
using ::llvm::BitmaskEnumDetail::operator&=; \
|
||||
/* Force a semicolon at the end of this macro. */ \
|
||||
using ::llvm::BitmaskEnumDetail::operator^=
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Traits class to determine whether an enum has a
|
||||
/// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator.
|
||||
template <typename E, typename Enable = void>
|
||||
struct is_bitmask_enum : std::false_type {};
|
||||
|
||||
template <typename E>
|
||||
struct is_bitmask_enum<
|
||||
E, typename std::enable_if<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >=
|
||||
0>::type> : std::true_type {};
|
||||
namespace BitmaskEnumDetail {
|
||||
|
||||
/// Get a bitmask with 1s in all places up to the high-order bit of E's largest
|
||||
/// value.
|
||||
template <typename E> typename std::underlying_type<E>::type Mask() {
|
||||
// On overflow, NextPowerOf2 returns zero with the type uint64_t, so
|
||||
// subtracting 1 gives us the mask with all bits set, like we want.
|
||||
return NextPowerOf2(static_cast<typename std::underlying_type<E>::type>(
|
||||
E::LLVM_BITMASK_LARGEST_ENUMERATOR)) -
|
||||
1;
|
||||
}
|
||||
|
||||
/// Check that Val is in range for E, and return Val cast to E's underlying
|
||||
/// type.
|
||||
template <typename E> typename std::underlying_type<E>::type Underlying(E Val) {
|
||||
auto U = static_cast<typename std::underlying_type<E>::type>(Val);
|
||||
assert(U >= 0 && "Negative enum values are not allowed.");
|
||||
assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)");
|
||||
return U;
|
||||
}
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E operator~(E Val) {
|
||||
return static_cast<E>(~Underlying(Val) & Mask<E>());
|
||||
}
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E operator|(E LHS, E RHS) {
|
||||
return static_cast<E>(Underlying(LHS) | Underlying(RHS));
|
||||
}
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E operator&(E LHS, E RHS) {
|
||||
return static_cast<E>(Underlying(LHS) & Underlying(RHS));
|
||||
}
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E operator^(E LHS, E RHS) {
|
||||
return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
|
||||
}
|
||||
|
||||
// |=, &=, and ^= return a reference to LHS, to match the behavior of the
|
||||
// operators on builtin types.
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E &operator|=(E &LHS, E RHS) {
|
||||
LHS = LHS | RHS;
|
||||
return LHS;
|
||||
}
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E &operator&=(E &LHS, E RHS) {
|
||||
LHS = LHS & RHS;
|
||||
return LHS;
|
||||
}
|
||||
|
||||
template <typename E,
|
||||
typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
|
||||
E &operator^=(E &LHS, E RHS) {
|
||||
LHS = LHS ^ RHS;
|
||||
return LHS;
|
||||
}
|
||||
|
||||
} // namespace BitmaskEnumDetail
|
||||
|
||||
// Enable bitmask enums in namespace ::llvm and all nested namespaces.
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -81,11 +81,13 @@ public:
|
||||
}
|
||||
unsigned size() const { return getNumEntries(); }
|
||||
|
||||
/// Grow the densemap so that it has at least Size buckets. Does not shrink
|
||||
void resize(size_type Size) {
|
||||
/// Grow the densemap so that it can contain at least \p NumEntries items
|
||||
/// before resizing again.
|
||||
void reserve(size_type NumEntries) {
|
||||
auto NumBuckets = getMinBucketToReserveForEntries(NumEntries);
|
||||
incrementEpoch();
|
||||
if (Size > getNumBuckets())
|
||||
grow(Size);
|
||||
if (NumBuckets > getNumBuckets())
|
||||
grow(NumBuckets);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@ -195,6 +197,26 @@ public:
|
||||
true);
|
||||
}
|
||||
|
||||
/// Alternate version of insert() which allows a different, and possibly
|
||||
/// less expensive, key type.
|
||||
/// The DenseMapInfo is responsible for supplying methods
|
||||
/// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
|
||||
/// type used.
|
||||
template <typename LookupKeyT>
|
||||
std::pair<iterator, bool> insert_as(std::pair<KeyT, ValueT> &&KV,
|
||||
const LookupKeyT &Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
|
||||
// Otherwise, insert the new element.
|
||||
TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val,
|
||||
TheBucket);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
}
|
||||
|
||||
/// insert - Range insertion of pairs.
|
||||
template<typename InputIt>
|
||||
void insert(InputIt I, InputIt E) {
|
||||
@ -285,6 +307,17 @@ protected:
|
||||
::new (&B->getFirst()) KeyT(EmptyKey);
|
||||
}
|
||||
|
||||
/// Returns the number of buckets to allocate to ensure that the DenseMap can
|
||||
/// accommodate \p NumEntries without need to grow().
|
||||
unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
|
||||
// Ensure that "NumEntries * 4 < NumBuckets * 3"
|
||||
if (NumEntries == 0)
|
||||
return 0;
|
||||
// +1 is required because of the strict equality.
|
||||
// For example if NumEntries is 48, we need to return 401.
|
||||
return NextPowerOf2(NumEntries * 4 / 3 + 1);
|
||||
}
|
||||
|
||||
void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
|
||||
initEmpty();
|
||||
|
||||
@ -399,7 +432,7 @@ private:
|
||||
|
||||
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
|
||||
BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
|
||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = Key;
|
||||
::new (&TheBucket->getSecond()) ValueT(Value);
|
||||
@ -408,7 +441,7 @@ private:
|
||||
|
||||
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
|
||||
BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
|
||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = Key;
|
||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
||||
@ -416,14 +449,26 @@ private:
|
||||
}
|
||||
|
||||
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
|
||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = std::move(Key);
|
||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
||||
return TheBucket;
|
||||
}
|
||||
|
||||
BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
|
||||
template <typename LookupKeyT>
|
||||
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup,
|
||||
BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = std::move(Key);
|
||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
||||
return TheBucket;
|
||||
}
|
||||
|
||||
template <typename LookupKeyT>
|
||||
BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
|
||||
BucketT *TheBucket) {
|
||||
incrementEpoch();
|
||||
|
||||
// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
|
||||
@ -439,12 +484,12 @@ private:
|
||||
unsigned NumBuckets = getNumBuckets();
|
||||
if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
|
||||
this->grow(NumBuckets * 2);
|
||||
LookupBucketFor(Key, TheBucket);
|
||||
LookupBucketFor(Lookup, TheBucket);
|
||||
NumBuckets = getNumBuckets();
|
||||
} else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <=
|
||||
NumBuckets/8)) {
|
||||
this->grow(NumBuckets);
|
||||
LookupBucketFor(Key, TheBucket);
|
||||
LookupBucketFor(Lookup, TheBucket);
|
||||
}
|
||||
assert(TheBucket);
|
||||
|
||||
@ -550,9 +595,9 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
unsigned NumBuckets;
|
||||
|
||||
public:
|
||||
explicit DenseMap(unsigned NumInitBuckets = 0) {
|
||||
init(NumInitBuckets);
|
||||
}
|
||||
/// Create a DenseMap wth an optional \p InitialReserve that guarantee that
|
||||
/// this number of elements can be inserted in the map without grow()
|
||||
explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); }
|
||||
|
||||
DenseMap(const DenseMap &other) : BaseT() {
|
||||
init(0);
|
||||
@ -566,7 +611,7 @@ public:
|
||||
|
||||
template<typename InputIt>
|
||||
DenseMap(const InputIt &I, const InputIt &E) {
|
||||
init(NextPowerOf2(std::distance(I, E)));
|
||||
init(std::distance(I, E));
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
@ -609,7 +654,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void init(unsigned InitBuckets) {
|
||||
void init(unsigned InitNumEntries) {
|
||||
auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries);
|
||||
if (allocateBuckets(InitBuckets)) {
|
||||
this->BaseT::initEmpty();
|
||||
} else {
|
||||
|
@ -30,6 +30,36 @@ struct DenseMapInfo {
|
||||
//static bool isEqual(const T &LHS, const T &RHS);
|
||||
};
|
||||
|
||||
template <typename T> struct CachedHash {
|
||||
CachedHash(T Val) : Val(std::move(Val)) {
|
||||
Hash = DenseMapInfo<T>::getHashValue(Val);
|
||||
}
|
||||
CachedHash(T Val, unsigned Hash) : Val(std::move(Val)), Hash(Hash) {}
|
||||
T Val;
|
||||
unsigned Hash;
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all CachedHash<T>.
|
||||
template <typename T> struct DenseMapInfo<CachedHash<T>> {
|
||||
static CachedHash<T> getEmptyKey() {
|
||||
T N = DenseMapInfo<T>::getEmptyKey();
|
||||
return {N, 0};
|
||||
}
|
||||
static CachedHash<T> getTombstoneKey() {
|
||||
T N = DenseMapInfo<T>::getTombstoneKey();
|
||||
return {N, 0};
|
||||
}
|
||||
static unsigned getHashValue(CachedHash<T> Val) {
|
||||
assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!");
|
||||
assert(!isEqual(Val, getTombstoneKey()) &&
|
||||
"Cannot hash the tombstone key!");
|
||||
return Val.Hash;
|
||||
}
|
||||
static bool isEqual(CachedHash<T> A, CachedHash<T> B) {
|
||||
return DenseMapInfo<T>::isEqual(A.Val, B.Val);
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pointers.
|
||||
template<typename T>
|
||||
struct DenseMapInfo<T*> {
|
||||
|
@ -94,6 +94,7 @@ public:
|
||||
ValueT *operator->() { return &I->getFirst(); }
|
||||
|
||||
Iterator& operator++() { ++I; return *this; }
|
||||
Iterator operator++(int) { auto T = *this; ++I; return T; }
|
||||
bool operator==(const Iterator& X) const { return I == X.I; }
|
||||
bool operator!=(const Iterator& X) const { return I != X.I; }
|
||||
};
|
||||
@ -115,6 +116,7 @@ public:
|
||||
const ValueT *operator->() { return &I->getFirst(); }
|
||||
|
||||
ConstIterator& operator++() { ++I; return *this; }
|
||||
ConstIterator operator++(int) { auto T = *this; ++I; return T; }
|
||||
bool operator==(const ConstIterator& X) const { return I == X.I; }
|
||||
bool operator!=(const ConstIterator& X) const { return I != X.I; }
|
||||
};
|
||||
@ -152,6 +154,19 @@ public:
|
||||
return TheMap.insert(std::make_pair(V, Empty));
|
||||
}
|
||||
|
||||
/// Alternative version of insert that uses a different (and possibly less
|
||||
/// expensive) key type.
|
||||
template <typename LookupKeyT>
|
||||
std::pair<iterator, bool> insert_as(const ValueT &V,
|
||||
const LookupKeyT &LookupKey) {
|
||||
return insert_as(ValueT(V), LookupKey);
|
||||
}
|
||||
template <typename LookupKeyT>
|
||||
std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) {
|
||||
detail::DenseSetEmpty Empty;
|
||||
return TheMap.insert_as(std::make_pair(std::move(V), Empty), LookupKey);
|
||||
}
|
||||
|
||||
// Range insertion of values.
|
||||
template<typename InputIt>
|
||||
void insert(InputIt I, InputIt E) {
|
||||
|
@ -17,10 +17,8 @@
|
||||
#define LLVM_ADT_FOLDINGSET_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
/// This folding set used for two purposes:
|
||||
@ -98,6 +96,7 @@ namespace llvm {
|
||||
/// The result indicates whether the node existed in the folding set.
|
||||
|
||||
class FoldingSetNodeID;
|
||||
class StringRef;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// FoldingSetImpl - Implements the folding set functionality. The main
|
||||
@ -181,11 +180,26 @@ public:
|
||||
/// empty - Returns true if there are no nodes in the folding set.
|
||||
bool empty() const { return NumNodes == 0; }
|
||||
|
||||
/// reserve - Increase the number of buckets such that adding the
|
||||
/// EltCount-th node won't cause a rebucket operation. reserve is permitted
|
||||
/// to allocate more space than requested by EltCount.
|
||||
void reserve(unsigned EltCount);
|
||||
/// capacity - Returns the number of nodes permitted in the folding set
|
||||
/// before a rebucket operation is performed.
|
||||
unsigned capacity() {
|
||||
// We allow a load factor of up to 2.0,
|
||||
// so that means our capacity is NumBuckets * 2
|
||||
return NumBuckets * 2;
|
||||
}
|
||||
|
||||
private:
|
||||
/// GrowHashTable - Double the size of the hash table and rehash everything.
|
||||
///
|
||||
void GrowHashTable();
|
||||
|
||||
/// GrowBucketCount - resize the hash table and rehash everything.
|
||||
/// NewBucketCount must be a power of two, and must be greater than the old
|
||||
/// bucket count.
|
||||
void GrowBucketCount(unsigned NewBucketCount);
|
||||
protected:
|
||||
/// GetNodeProfile - Instantiations of the FoldingSet template implement
|
||||
/// this function to gather data bits for the given node.
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@ -632,7 +631,8 @@ inline hash_code hash_integer_value(uint64_t value) {
|
||||
template <typename T>
|
||||
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
|
||||
hash_value(T value) {
|
||||
return ::llvm::hashing::detail::hash_integer_value(value);
|
||||
return ::llvm::hashing::detail::hash_integer_value(
|
||||
static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define LLVM_ADT_POINTEREMBEDDEDINT_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <climits>
|
||||
|
||||
@ -30,6 +31,8 @@ template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT>
|
||||
class PointerEmbeddedInt {
|
||||
uintptr_t Value;
|
||||
|
||||
// Note: This '<' is correct; using '<=' would result in some shifts
|
||||
// overflowing their storage types.
|
||||
static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
|
||||
"Cannot embed more bits than we have in a pointer!");
|
||||
|
||||
@ -42,25 +45,36 @@ class PointerEmbeddedInt {
|
||||
Mask = static_cast<uintptr_t>(-1) << Bits
|
||||
};
|
||||
|
||||
struct RawValueTag {
|
||||
explicit RawValueTag() = default;
|
||||
};
|
||||
|
||||
friend class PointerLikeTypeTraits<PointerEmbeddedInt>;
|
||||
|
||||
explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {}
|
||||
explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {}
|
||||
|
||||
public:
|
||||
PointerEmbeddedInt() : Value(0) {}
|
||||
|
||||
PointerEmbeddedInt(IntT I) : Value(static_cast<uintptr_t>(I) << Shift) {
|
||||
assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
|
||||
PointerEmbeddedInt(IntT I) {
|
||||
*this = I;
|
||||
}
|
||||
|
||||
PointerEmbeddedInt &operator=(IntT I) {
|
||||
assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
|
||||
assert((std::is_signed<IntT>::value ? llvm::isInt<Bits>(I)
|
||||
: llvm::isUInt<Bits>(I)) &&
|
||||
"Integer has bits outside those preserved!");
|
||||
Value = static_cast<uintptr_t>(I) << Shift;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Note that this imilict conversion additionally allows all of the basic
|
||||
// Note that this implicit conversion additionally allows all of the basic
|
||||
// comparison operators to work transparently, etc.
|
||||
operator IntT() const { return static_cast<IntT>(Value >> Shift); }
|
||||
operator IntT() const {
|
||||
if (std::is_signed<IntT>::value)
|
||||
return static_cast<IntT>(static_cast<intptr_t>(Value) >> Shift);
|
||||
return static_cast<IntT>(Value >> Shift);
|
||||
}
|
||||
};
|
||||
|
||||
// Provide pointer like traits to support use with pointer unions and sum
|
||||
@ -74,10 +88,10 @@ public:
|
||||
return reinterpret_cast<void *>(P.Value);
|
||||
}
|
||||
static inline T getFromVoidPointer(void *P) {
|
||||
return T(reinterpret_cast<uintptr_t>(P));
|
||||
return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
|
||||
}
|
||||
static inline T getFromVoidPointer(const void *P) {
|
||||
return T(reinterpret_cast<uintptr_t>(P));
|
||||
return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
|
||||
}
|
||||
|
||||
enum { NumLowBitsAvailable = T::Shift };
|
||||
|
@ -28,7 +28,7 @@ namespace llvm {
|
||||
// visited nodes during the po_iterator's depth-first traversal.
|
||||
//
|
||||
// The default implementation simply contains a set of visited nodes, while
|
||||
// the Extended=true version uses a reference to an external set.
|
||||
// the External=true version uses a reference to an external set.
|
||||
//
|
||||
// It is possible to prune the depth-first traversal in several ways:
|
||||
//
|
||||
|
224
contrib/llvm/include/llvm/ADT/PriorityWorklist.h
Normal file
224
contrib/llvm/include/llvm/ADT/PriorityWorklist.h
Normal file
@ -0,0 +1,224 @@
|
||||
//===- PriorityWorklist.h - Worklist with insertion priority ----*- 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 priority worklist. See the class comments for details.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_PRIORITYWORKLIST_H
|
||||
#define LLVM_ADT_PRIORITYWORKLIST_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A FILO worklist that prioritizes on re-insertion without duplication.
|
||||
///
|
||||
/// This is very similar to a \c SetVector with the primary difference that
|
||||
/// while re-insertion does not create a duplicate, it does adjust the
|
||||
/// visitation order to respect the last insertion point. This can be useful
|
||||
/// when the visit order needs to be prioritized based on insertion point
|
||||
/// without actually having duplicate visits.
|
||||
///
|
||||
/// Note that this doesn't prevent re-insertion of elements which have been
|
||||
/// visited -- if you need to break cycles, a set will still be necessary.
|
||||
///
|
||||
/// The type \c T must be default constructable to a null value that will be
|
||||
/// ignored. It is an error to insert such a value, and popping elements will
|
||||
/// never produce such a value. It is expected to be used with common nullable
|
||||
/// types like pointers or optionals.
|
||||
///
|
||||
/// Internally this uses a vector to store the worklist and a map to identify
|
||||
/// existing elements in the worklist. Both of these may be customized, but the
|
||||
/// map must support the basic DenseMap API for mapping from a T to an integer
|
||||
/// index into the vector.
|
||||
///
|
||||
/// A partial specialization is provided to automatically select a SmallVector
|
||||
/// and a SmallDenseMap if custom data structures are not provided.
|
||||
template <typename T, typename VectorT = std::vector<T>,
|
||||
typename MapT = DenseMap<T, ptrdiff_t>>
|
||||
class PriorityWorklist {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T key_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef typename MapT::size_type size_type;
|
||||
|
||||
/// Construct an empty PriorityWorklist
|
||||
PriorityWorklist() {}
|
||||
|
||||
/// Determine if the PriorityWorklist is empty or not.
|
||||
bool empty() const {
|
||||
return V.empty();
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the worklist.
|
||||
size_type size() const {
|
||||
return M.size();
|
||||
}
|
||||
|
||||
/// Count the number of elements of a given key in the PriorityWorklist.
|
||||
/// \returns 0 if the element is not in the PriorityWorklist, 1 if it is.
|
||||
size_type count(const key_type &key) const {
|
||||
return M.count(key);
|
||||
}
|
||||
|
||||
/// Return the last element of the PriorityWorklist.
|
||||
const T &back() const {
|
||||
assert(!empty() && "Cannot call back() on empty PriorityWorklist!");
|
||||
return V.back();
|
||||
}
|
||||
|
||||
/// Insert a new element into the PriorityWorklist.
|
||||
/// \returns true if the element was inserted into the PriorityWorklist.
|
||||
bool insert(const T &X) {
|
||||
assert(X != T() && "Cannot insert a null (default constructed) value!");
|
||||
auto InsertResult = M.insert({X, V.size()});
|
||||
if (InsertResult.second) {
|
||||
// Fresh value, just append it to the vector.
|
||||
V.push_back(X);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto &Index = InsertResult.first->second;
|
||||
assert(V[Index] == X && "Value not actually at index in map!");
|
||||
if (Index != (ptrdiff_t)(V.size() - 1)) {
|
||||
// If the element isn't at the back, null it out and append a fresh one.
|
||||
V[Index] = T();
|
||||
Index = (ptrdiff_t)V.size();
|
||||
V.push_back(X);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Remove the last element of the PriorityWorklist.
|
||||
void pop_back() {
|
||||
assert(!empty() && "Cannot remove an element when empty!");
|
||||
assert(back() != T() && "Cannot have a null element at the back!");
|
||||
M.erase(back());
|
||||
do {
|
||||
V.pop_back();
|
||||
} while (!V.empty() && V.back() == T());
|
||||
}
|
||||
|
||||
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
|
||||
T Ret = back();
|
||||
pop_back();
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/// Erase an item from the worklist.
|
||||
///
|
||||
/// Note that this is constant time due to the nature of the worklist implementation.
|
||||
bool erase(const T& X) {
|
||||
auto I = M.find(X);
|
||||
if (I == M.end())
|
||||
return false;
|
||||
|
||||
assert(V[I->second] == X && "Value not actually at index in map!");
|
||||
if (I->second == (ptrdiff_t)(V.size() - 1)) {
|
||||
do {
|
||||
V.pop_back();
|
||||
} while (!V.empty() && V.back() == T());
|
||||
} else {
|
||||
V[I->second] = T();
|
||||
}
|
||||
M.erase(I);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Erase items from the set vector based on a predicate function.
|
||||
///
|
||||
/// This is intended to be equivalent to the following code, if we could
|
||||
/// write it:
|
||||
///
|
||||
/// \code
|
||||
/// V.erase(std::remove_if(V.begin(), V.end(), P), V.end());
|
||||
/// \endcode
|
||||
///
|
||||
/// However, PriorityWorklist doesn't expose non-const iterators, making any
|
||||
/// algorithm like remove_if impossible to use.
|
||||
///
|
||||
/// \returns true if any element is removed.
|
||||
template <typename UnaryPredicate>
|
||||
bool erase_if(UnaryPredicate P) {
|
||||
typename VectorT::iterator E = std::remove_if(
|
||||
V.begin(), V.end(), TestAndEraseFromMap<UnaryPredicate>(P, M));
|
||||
if (E == V.end())
|
||||
return false;
|
||||
for (auto I = V.begin(); I != E; ++I)
|
||||
if (*I != T())
|
||||
M[*I] = I - V.begin();
|
||||
V.erase(E, V.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Completely clear the PriorityWorklist
|
||||
void clear() {
|
||||
M.clear();
|
||||
V.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
/// A wrapper predicate designed for use with std::remove_if.
|
||||
///
|
||||
/// This predicate wraps a predicate suitable for use with std::remove_if to
|
||||
/// call M.erase(x) on each element which is slated for removal. This just
|
||||
/// allows the predicate to be move only which we can't do with lambdas
|
||||
/// today.
|
||||
template <typename UnaryPredicateT>
|
||||
class TestAndEraseFromMap {
|
||||
UnaryPredicateT P;
|
||||
MapT &M;
|
||||
|
||||
public:
|
||||
TestAndEraseFromMap(UnaryPredicateT P, MapT &M)
|
||||
: P(std::move(P)), M(M) {}
|
||||
|
||||
bool operator()(const T &Arg) {
|
||||
if (Arg == T())
|
||||
// Skip null values in the PriorityWorklist.
|
||||
return false;
|
||||
|
||||
if (P(Arg)) {
|
||||
M.erase(Arg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// The map from value to index in the vector.
|
||||
MapT M;
|
||||
|
||||
/// The vector of elements in insertion order.
|
||||
VectorT V;
|
||||
};
|
||||
|
||||
/// A version of \c PriorityWorklist that selects small size optimized data
|
||||
/// structures for the vector and map.
|
||||
template <typename T, unsigned N>
|
||||
class SmallPriorityWorklist
|
||||
: public PriorityWorklist<T, SmallVector<T, N>,
|
||||
SmallDenseMap<T, ptrdiff_t>> {
|
||||
public:
|
||||
SmallPriorityWorklist() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -17,7 +17,6 @@
|
||||
#ifndef LLVM_ADT_STLEXTRAS_H
|
||||
#define LLVM_ADT_STLEXTRAS_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <algorithm> // for std::all_of
|
||||
#include <cassert>
|
||||
#include <cstddef> // for std::size_t
|
||||
@ -27,6 +26,9 @@
|
||||
#include <memory>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -117,7 +119,9 @@ public:
|
||||
iterator_category;
|
||||
typedef typename std::iterator_traits<RootIt>::difference_type
|
||||
difference_type;
|
||||
typedef typename UnaryFunc::result_type value_type;
|
||||
typedef typename std::result_of<
|
||||
UnaryFunc(decltype(*std::declval<RootIt>()))>
|
||||
::type value_type;
|
||||
|
||||
typedef void pointer;
|
||||
//typedef typename UnaryFunc::result_type *pointer;
|
||||
@ -379,6 +383,14 @@ bool any_of(R &&Range, UnaryPredicate &&P) {
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::none_of which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template <typename R, class UnaryPredicate>
|
||||
bool none_of(R &&Range, UnaryPredicate &&P) {
|
||||
return std::none_of(Range.begin(), Range.end(),
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::find which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template<typename R, class T>
|
||||
@ -386,6 +398,43 @@ auto find(R &&Range, const T &val) -> decltype(Range.begin()) {
|
||||
return std::find(Range.begin(), Range.end(), val);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::find_if which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template <typename R, class T>
|
||||
auto find_if(R &&Range, const T &Pred) -> decltype(Range.begin()) {
|
||||
return std::find_if(Range.begin(), Range.end(), Pred);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::remove_if which take ranges instead of having to
|
||||
/// pass begin/end explicitly.
|
||||
template<typename R, class UnaryPredicate>
|
||||
auto remove_if(R &&Range, UnaryPredicate &&P) -> decltype(Range.begin()) {
|
||||
return std::remove_if(Range.begin(), Range.end(), P);
|
||||
}
|
||||
|
||||
/// Wrapper function around std::find to detect if an element exists
|
||||
/// in a container.
|
||||
template <typename R, typename E>
|
||||
bool is_contained(R &&Range, const E &Element) {
|
||||
return std::find(Range.begin(), Range.end(), Element) != Range.end();
|
||||
}
|
||||
|
||||
/// Wrapper function around std::count_if to count the number of times an
|
||||
/// element satisfying a given predicate occurs in a range.
|
||||
template <typename R, typename UnaryPredicate>
|
||||
auto count_if(R &&Range, UnaryPredicate &&P)
|
||||
-> typename std::iterator_traits<decltype(Range.begin())>::difference_type {
|
||||
return std::count_if(Range.begin(), Range.end(), P);
|
||||
}
|
||||
|
||||
/// Wrapper function around std::transform to apply a function to a range and
|
||||
/// store the result elsewhere.
|
||||
template <typename R, class OutputIt, typename UnaryPredicate>
|
||||
OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate &&P) {
|
||||
return std::transform(Range.begin(), Range.end(), d_first,
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <memory>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
79
contrib/llvm/include/llvm/ADT/Sequence.h
Normal file
79
contrib/llvm/include/llvm/ADT/Sequence.h
Normal file
@ -0,0 +1,79 @@
|
||||
//===- Sequence.h - Utility for producing sequences of values ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This routine provides some synthesis utilities to produce sequences of
|
||||
/// values. The names are intentionally kept very short as they tend to occur
|
||||
/// in common and widely used contexts.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SEQ_H
|
||||
#define LLVM_ADT_SEQ_H
|
||||
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace detail {
|
||||
template <typename ValueT>
|
||||
class value_sequence_iterator
|
||||
: public iterator_facade_base<value_sequence_iterator<ValueT>,
|
||||
std::random_access_iterator_tag,
|
||||
const ValueT> {
|
||||
typedef typename value_sequence_iterator::iterator_facade_base BaseT;
|
||||
|
||||
ValueT Value;
|
||||
|
||||
public:
|
||||
typedef typename BaseT::difference_type difference_type;
|
||||
typedef typename BaseT::reference reference;
|
||||
|
||||
value_sequence_iterator() = default;
|
||||
value_sequence_iterator(const value_sequence_iterator &) = default;
|
||||
value_sequence_iterator(value_sequence_iterator &&Arg)
|
||||
: Value(std::move(Arg.Value)) {}
|
||||
|
||||
template <typename U, typename Enabler = decltype(ValueT(std::declval<U>()))>
|
||||
value_sequence_iterator(U &&Value) : Value(std::forward<U>(Value)) {}
|
||||
|
||||
value_sequence_iterator &operator+=(difference_type N) {
|
||||
Value += N;
|
||||
return *this;
|
||||
}
|
||||
value_sequence_iterator &operator-=(difference_type N) {
|
||||
Value -= N;
|
||||
return *this;
|
||||
}
|
||||
using BaseT::operator-;
|
||||
difference_type operator-(const value_sequence_iterator &RHS) const {
|
||||
return Value - RHS.Value;
|
||||
}
|
||||
|
||||
bool operator==(const value_sequence_iterator &RHS) const {
|
||||
return Value == RHS.Value;
|
||||
}
|
||||
bool operator<(const value_sequence_iterator &RHS) const {
|
||||
return Value < RHS.Value;
|
||||
}
|
||||
|
||||
reference operator*() const { return Value; }
|
||||
};
|
||||
} // End detail namespace.
|
||||
|
||||
template <typename ValueT>
|
||||
iterator_range<detail::value_sequence_iterator<ValueT>> seq(ValueT Begin,
|
||||
ValueT End) {
|
||||
return make_range(detail::value_sequence_iterator<ValueT>(Begin),
|
||||
detail::value_sequence_iterator<ValueT>(End));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -24,6 +24,7 @@
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -123,7 +124,7 @@ public:
|
||||
}
|
||||
|
||||
/// \brief Insert a new element into the SetVector.
|
||||
/// \returns true iff the element was inserted into the SetVector.
|
||||
/// \returns true if the element was inserted into the SetVector.
|
||||
bool insert(const value_type &X) {
|
||||
bool result = set_.insert(X).second;
|
||||
if (result)
|
||||
@ -151,6 +152,24 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Erase a single element from the set vector.
|
||||
/// \returns an iterator pointing to the next element that followed the
|
||||
/// element erased. This is the end of the SetVector if the last element is
|
||||
/// erased.
|
||||
iterator erase(iterator I) {
|
||||
const key_type &V = *I;
|
||||
assert(set_.count(V) && "Corrupted SetVector instances!");
|
||||
set_.erase(V);
|
||||
|
||||
// FIXME: No need to use the non-const iterator when built with
|
||||
// std:vector.erase(const_iterator) as defined in C++11. This is for
|
||||
// compatibility with non-standard libstdc++ up to 4.8 (fixed in 4.9).
|
||||
auto NI = vector_.begin();
|
||||
std::advance(NI, std::distance<iterator>(NI, I));
|
||||
|
||||
return vector_.erase(NI);
|
||||
}
|
||||
|
||||
/// \brief Remove items from the set vector based on a predicate function.
|
||||
///
|
||||
/// This is intended to be equivalent to the following code, if we could
|
||||
@ -207,6 +226,31 @@ public:
|
||||
bool operator!=(const SetVector &that) const {
|
||||
return vector_ != that.vector_;
|
||||
}
|
||||
|
||||
/// \brief Compute This := This u S, return whether 'This' changed.
|
||||
/// TODO: We should be able to use set_union from SetOperations.h, but
|
||||
/// SetVector interface is inconsistent with DenseSet.
|
||||
template <class STy>
|
||||
bool set_union(const STy &S) {
|
||||
bool Changed = false;
|
||||
|
||||
for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE;
|
||||
++SI)
|
||||
if (insert(*SI))
|
||||
Changed = true;
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// \brief Compute This := This - B
|
||||
/// TODO: We should be able to use set_subtract from SetOperations.h, but
|
||||
/// SetVector interface is inconsistent with DenseSet.
|
||||
template <class STy>
|
||||
void set_subtract(const STy &S) {
|
||||
for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE;
|
||||
++SI)
|
||||
remove(*SI);
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief A wrapper predicate designed for use with std::remove_if.
|
||||
@ -219,7 +263,8 @@ private:
|
||||
set_type &set_;
|
||||
|
||||
public:
|
||||
TestAndEraseFromSet(UnaryPredicate P, set_type &set_) : P(P), set_(set_) {}
|
||||
TestAndEraseFromSet(UnaryPredicate P, set_type &set_)
|
||||
: P(std::move(P)), set_(set_) {}
|
||||
|
||||
template <typename ArgumentT>
|
||||
bool operator()(const ArgumentT &Arg) {
|
||||
|
@ -15,19 +15,16 @@
|
||||
#define LLVM_ADT_SMALLBITVECTOR_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// SmallBitVector - This is a 'bitvector' (really, a variable-sized bit array),
|
||||
/// optimized for the case when the array is small. It contains one
|
||||
/// pointer-sized field, which is directly used as a plain collection of bits
|
||||
/// when possible, or as a pointer to a larger heap-allocated array when
|
||||
/// necessary. This allows normal "small" cases to be fast without losing
|
||||
/// generality for large inputs.
|
||||
///
|
||||
/// This is a 'bitvector' (really, a variable-sized bit array), optimized for
|
||||
/// the case when the array is small. It contains one pointer-sized field, which
|
||||
/// is directly used as a plain collection of bits when possible, or as a
|
||||
/// pointer to a larger heap-allocated array when necessary. This allows normal
|
||||
/// "small" cases to be fast without losing generality for large inputs.
|
||||
class SmallBitVector {
|
||||
// TODO: In "large" mode, a pointer to a BitVector is used, leading to an
|
||||
// unnecessary level of indirection. It would be more efficient to use a
|
||||
@ -139,11 +136,11 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
/// SmallBitVector default ctor - Creates an empty bitvector.
|
||||
/// Creates an empty bitvector.
|
||||
SmallBitVector() : X(1) {}
|
||||
|
||||
/// SmallBitVector ctor - Creates a bitvector of specified number of bits. All
|
||||
/// bits are initialized to the specified value.
|
||||
/// Creates a bitvector of specified number of bits. All bits are initialized
|
||||
/// to the specified value.
|
||||
explicit SmallBitVector(unsigned s, bool t = false) {
|
||||
if (s <= SmallNumDataBits)
|
||||
switchToSmall(t ? ~uintptr_t(0) : 0, s);
|
||||
@ -168,17 +165,17 @@ public:
|
||||
delete getPointer();
|
||||
}
|
||||
|
||||
/// empty - Tests whether there are no bits in this bitvector.
|
||||
/// Tests whether there are no bits in this bitvector.
|
||||
bool empty() const {
|
||||
return isSmall() ? getSmallSize() == 0 : getPointer()->empty();
|
||||
}
|
||||
|
||||
/// size - Returns the number of bits in this bitvector.
|
||||
/// Returns the number of bits in this bitvector.
|
||||
size_t size() const {
|
||||
return isSmall() ? getSmallSize() : getPointer()->size();
|
||||
}
|
||||
|
||||
/// count - Returns the number of bits which are set.
|
||||
/// Returns the number of bits which are set.
|
||||
size_type count() const {
|
||||
if (isSmall()) {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
@ -187,29 +184,28 @@ public:
|
||||
return getPointer()->count();
|
||||
}
|
||||
|
||||
/// any - Returns true if any bit is set.
|
||||
/// Returns true if any bit is set.
|
||||
bool any() const {
|
||||
if (isSmall())
|
||||
return getSmallBits() != 0;
|
||||
return getPointer()->any();
|
||||
}
|
||||
|
||||
/// all - Returns true if all bits are set.
|
||||
/// Returns true if all bits are set.
|
||||
bool all() const {
|
||||
if (isSmall())
|
||||
return getSmallBits() == (uintptr_t(1) << getSmallSize()) - 1;
|
||||
return getPointer()->all();
|
||||
}
|
||||
|
||||
/// none - Returns true if none of the bits are set.
|
||||
/// Returns true if none of the bits are set.
|
||||
bool none() const {
|
||||
if (isSmall())
|
||||
return getSmallBits() == 0;
|
||||
return getPointer()->none();
|
||||
}
|
||||
|
||||
/// find_first - Returns the index of the first set bit, -1 if none
|
||||
/// of the bits are set.
|
||||
/// Returns the index of the first set bit, -1 if none of the bits are set.
|
||||
int find_first() const {
|
||||
if (isSmall()) {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
@ -220,8 +216,8 @@ public:
|
||||
return getPointer()->find_first();
|
||||
}
|
||||
|
||||
/// find_next - Returns the index of the next set bit following the
|
||||
/// "Prev" bit. Returns -1 if the next set bit is not found.
|
||||
/// Returns the index of the next set bit following the "Prev" bit.
|
||||
/// Returns -1 if the next set bit is not found.
|
||||
int find_next(unsigned Prev) const {
|
||||
if (isSmall()) {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
@ -234,14 +230,14 @@ public:
|
||||
return getPointer()->find_next(Prev);
|
||||
}
|
||||
|
||||
/// clear - Clear all bits.
|
||||
/// Clear all bits.
|
||||
void clear() {
|
||||
if (!isSmall())
|
||||
delete getPointer();
|
||||
switchToSmall(0, 0);
|
||||
}
|
||||
|
||||
/// resize - Grow or shrink the bitvector.
|
||||
/// Grow or shrink the bitvector.
|
||||
void resize(unsigned N, bool t = false) {
|
||||
if (!isSmall()) {
|
||||
getPointer()->resize(N, t);
|
||||
@ -296,7 +292,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// set - Efficiently set a range of bits in [I, E)
|
||||
/// Efficiently set a range of bits in [I, E)
|
||||
SmallBitVector &set(unsigned I, unsigned E) {
|
||||
assert(I <= E && "Attempted to set backwards range!");
|
||||
assert(E <= size() && "Attempted to set out-of-bounds range!");
|
||||
@ -327,7 +323,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// reset - Efficiently reset a range of bits in [I, E)
|
||||
/// Efficiently reset a range of bits in [I, E)
|
||||
SmallBitVector &reset(unsigned I, unsigned E) {
|
||||
assert(I <= E && "Attempted to reset backwards range!");
|
||||
assert(E <= size() && "Attempted to reset out-of-bounds range!");
|
||||
@ -422,7 +418,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// reset - Reset bits that are set in RHS. Same as *this &= ~RHS.
|
||||
/// Reset bits that are set in RHS. Same as *this &= ~RHS.
|
||||
SmallBitVector &reset(const SmallBitVector &RHS) {
|
||||
if (isSmall() && RHS.isSmall())
|
||||
setSmallBits(getSmallBits() & ~RHS.getSmallBits());
|
||||
@ -436,8 +432,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// test - Check if (This - RHS) is zero.
|
||||
/// This is the same as reset(RHS) and any().
|
||||
/// Check if (This - RHS) is zero. This is the same as reset(RHS) and any().
|
||||
bool test(const SmallBitVector &RHS) const {
|
||||
if (isSmall() && RHS.isSmall())
|
||||
return (getSmallBits() & ~RHS.getSmallBits()) != 0;
|
||||
@ -514,7 +509,7 @@ public:
|
||||
std::swap(X, RHS.X);
|
||||
}
|
||||
|
||||
/// setBitsInMask - Add '1' bits from Mask to this vector. Don't resize.
|
||||
/// Add '1' bits from Mask to this vector. Don't resize.
|
||||
/// This computes "*this |= Mask".
|
||||
void setBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) {
|
||||
if (isSmall())
|
||||
@ -523,8 +518,8 @@ public:
|
||||
getPointer()->setBitsInMask(Mask, MaskWords);
|
||||
}
|
||||
|
||||
/// clearBitsInMask - Clear any bits in this vector that are set in Mask.
|
||||
/// Don't resize. This computes "*this &= ~Mask".
|
||||
/// Clear any bits in this vector that are set in Mask. Don't resize.
|
||||
/// This computes "*this &= ~Mask".
|
||||
void clearBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) {
|
||||
if (isSmall())
|
||||
applyMask<false, false>(Mask, MaskWords);
|
||||
@ -532,8 +527,8 @@ public:
|
||||
getPointer()->clearBitsInMask(Mask, MaskWords);
|
||||
}
|
||||
|
||||
/// setBitsNotInMask - Add a bit to this vector for every '0' bit in Mask.
|
||||
/// Don't resize. This computes "*this |= ~Mask".
|
||||
/// Add a bit to this vector for every '0' bit in Mask. Don't resize.
|
||||
/// This computes "*this |= ~Mask".
|
||||
void setBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) {
|
||||
if (isSmall())
|
||||
applyMask<true, true>(Mask, MaskWords);
|
||||
@ -541,8 +536,8 @@ public:
|
||||
getPointer()->setBitsNotInMask(Mask, MaskWords);
|
||||
}
|
||||
|
||||
/// clearBitsNotInMask - Clear a bit in this vector for every '0' bit in Mask.
|
||||
/// Don't resize. This computes "*this &= Mask".
|
||||
/// Clear a bit in this vector for every '0' bit in Mask. Don't resize.
|
||||
/// This computes "*this &= Mask".
|
||||
void clearBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) {
|
||||
if (isSmall())
|
||||
applyMask<false, true>(Mask, MaskWords);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
@ -58,36 +59,45 @@ protected:
|
||||
/// CurArraySize - The allocated size of CurArray, always a power of two.
|
||||
unsigned CurArraySize;
|
||||
|
||||
// If small, this is # elts allocated consecutively
|
||||
unsigned NumElements;
|
||||
/// Number of elements in CurArray that contain a value or are a tombstone.
|
||||
/// If small, all these elements are at the beginning of CurArray and the rest
|
||||
/// is uninitialized.
|
||||
unsigned NumNonEmpty;
|
||||
/// Number of tombstones in CurArray.
|
||||
unsigned NumTombstones;
|
||||
|
||||
// Helpers to copy and move construct a SmallPtrSet.
|
||||
SmallPtrSetImplBase(const void **SmallStorage, const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that);
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) :
|
||||
SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) {
|
||||
SmallPtrSetImplBase &&that);
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallArray(SmallStorage), CurArray(SmallStorage),
|
||||
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
|
||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||
"Initial size must be a power of two!");
|
||||
clear();
|
||||
}
|
||||
~SmallPtrSetImplBase();
|
||||
~SmallPtrSetImplBase() {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
|
||||
size_type size() const { return NumElements; }
|
||||
size_type size() const { return NumNonEmpty - NumTombstones; }
|
||||
|
||||
void clear() {
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
// shrink the array.
|
||||
if (!isSmall() && NumElements*4 < CurArraySize && CurArraySize > 32)
|
||||
return shrink_and_clear();
|
||||
if (!isSmall()) {
|
||||
if (size() * 4 < CurArraySize && CurArraySize > 32)
|
||||
return shrink_and_clear();
|
||||
// Fill the array with empty markers.
|
||||
memset(CurArray, -1, CurArraySize * sizeof(void *));
|
||||
}
|
||||
|
||||
// Fill the array with empty markers.
|
||||
memset(CurArray, -1, CurArraySize*sizeof(void*));
|
||||
NumElements = 0;
|
||||
NumNonEmpty = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
@ -99,10 +109,42 @@ protected:
|
||||
return reinterpret_cast<void*>(-1);
|
||||
}
|
||||
|
||||
const void **EndPointer() const {
|
||||
return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
|
||||
}
|
||||
|
||||
/// insert_imp - This returns true if the pointer was new to the set, false if
|
||||
/// it was already in the set. This is hidden from the client so that the
|
||||
/// derived class can check that the right type of pointer is passed in.
|
||||
std::pair<const void *const *, bool> insert_imp(const void *Ptr);
|
||||
std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
|
||||
if (isSmall()) {
|
||||
// Check to see if it is already in the set.
|
||||
const void **LastTombstone = nullptr;
|
||||
for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
|
||||
APtr != E; ++APtr) {
|
||||
const void *Value = *APtr;
|
||||
if (Value == Ptr)
|
||||
return std::make_pair(APtr, false);
|
||||
if (Value == getTombstoneMarker())
|
||||
LastTombstone = APtr;
|
||||
}
|
||||
|
||||
// Did we find any tombstone marker?
|
||||
if (LastTombstone != nullptr) {
|
||||
*LastTombstone = Ptr;
|
||||
--NumTombstones;
|
||||
return std::make_pair(LastTombstone, true);
|
||||
}
|
||||
|
||||
// Nope, there isn't. If we stay small, just 'pushback' now.
|
||||
if (NumNonEmpty < CurArraySize) {
|
||||
SmallArray[NumNonEmpty++] = Ptr;
|
||||
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
|
||||
}
|
||||
// Otherwise, hit the big set case, which will call grow.
|
||||
}
|
||||
return insert_imp_big(Ptr);
|
||||
}
|
||||
|
||||
/// erase_imp - If the set contains the specified pointer, remove it and
|
||||
/// return true, otherwise return false. This is hidden from the client so
|
||||
@ -114,7 +156,7 @@ protected:
|
||||
if (isSmall()) {
|
||||
// Linear search for the item.
|
||||
for (const void *const *APtr = SmallArray,
|
||||
*const *E = SmallArray+NumElements; APtr != E; ++APtr)
|
||||
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
|
||||
if (*APtr == Ptr)
|
||||
return true;
|
||||
return false;
|
||||
@ -127,6 +169,8 @@ protected:
|
||||
private:
|
||||
bool isSmall() const { return CurArray == SmallArray; }
|
||||
|
||||
std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
|
||||
|
||||
const void * const *FindBucketFor(const void *Ptr) const;
|
||||
void shrink_and_clear();
|
||||
|
||||
@ -142,6 +186,12 @@ protected:
|
||||
|
||||
void CopyFrom(const SmallPtrSetImplBase &RHS);
|
||||
void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
|
||||
private:
|
||||
/// Code shared by MoveFrom() and move constructor.
|
||||
void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
/// Code shared by CopyFrom() and copy constructor.
|
||||
void CopyHelper(const SmallPtrSetImplBase &RHS);
|
||||
};
|
||||
|
||||
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||
@ -154,7 +204,7 @@ protected:
|
||||
public:
|
||||
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
|
||||
: Bucket(BP), End(E) {
|
||||
AdvanceIfNotValid();
|
||||
AdvanceIfNotValid();
|
||||
}
|
||||
|
||||
bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
@ -266,7 +316,7 @@ public:
|
||||
/// the element equal to Ptr.
|
||||
std::pair<iterator, bool> insert(PtrType Ptr) {
|
||||
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return std::make_pair(iterator(p.first, CurArray + CurArraySize), p.second);
|
||||
return std::make_pair(iterator(p.first, EndPointer()), p.second);
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
@ -287,10 +337,11 @@ public:
|
||||
}
|
||||
|
||||
inline iterator begin() const {
|
||||
return iterator(CurArray, CurArray+CurArraySize);
|
||||
return iterator(CurArray, EndPointer());
|
||||
}
|
||||
inline iterator end() const {
|
||||
return iterator(CurArray+CurArraySize, CurArray+CurArraySize);
|
||||
const void *const *End = EndPointer();
|
||||
return iterator(End, End);
|
||||
}
|
||||
};
|
||||
|
||||
@ -300,6 +351,11 @@ public:
|
||||
/// SmallPtrSetImplBase for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(SmallSize <= 32, "SmallSize should be small");
|
||||
|
||||
typedef SmallPtrSetImpl<PtrType> BaseT;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
|
@ -38,6 +38,11 @@ class SmallSet {
|
||||
typedef typename SmallVector<T, N>::const_iterator VIterator;
|
||||
typedef typename SmallVector<T, N>::iterator mutable_iterator;
|
||||
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(N <= 32, "N should be small");
|
||||
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
SmallSet() {}
|
||||
|
@ -184,33 +184,12 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
/// Use move-assignment to move the range [I, E) onto the
|
||||
/// objects starting with "Dest". This is just <memory>'s
|
||||
/// std::move, but not all stdlibs actually provide that.
|
||||
template<typename It1, typename It2>
|
||||
static It2 move(It1 I, It1 E, It2 Dest) {
|
||||
for (; I != E; ++I, ++Dest)
|
||||
*Dest = ::std::move(*I);
|
||||
return Dest;
|
||||
}
|
||||
|
||||
/// Use move-assignment to move the range
|
||||
/// [I, E) onto the objects ending at "Dest", moving objects
|
||||
/// in reverse order. This is just <algorithm>'s
|
||||
/// std::move_backward, but not all stdlibs actually provide that.
|
||||
template<typename It1, typename It2>
|
||||
static It2 move_backward(It1 I, It1 E, It2 Dest) {
|
||||
while (I != E)
|
||||
*--Dest = ::std::move(*--E);
|
||||
return Dest;
|
||||
}
|
||||
|
||||
/// Move the range [I, E) into the uninitialized memory starting with "Dest",
|
||||
/// constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
for (; I != E; ++I, ++Dest)
|
||||
::new ((void*) &*Dest) T(::std::move(*I));
|
||||
std::uninitialized_copy(std::make_move_iterator(I),
|
||||
std::make_move_iterator(E), Dest);
|
||||
}
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
|
||||
@ -283,20 +262,6 @@ protected:
|
||||
// No need to do a destroy loop for POD's.
|
||||
static void destroy_range(T *, T *) {}
|
||||
|
||||
/// Use move-assignment to move the range [I, E) onto the
|
||||
/// objects starting with "Dest". For PODs, this is just memcpy.
|
||||
template<typename It1, typename It2>
|
||||
static It2 move(It1 I, It1 E, It2 Dest) {
|
||||
return ::std::copy(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Use move-assignment to move the range [I, E) onto the objects ending at
|
||||
/// "Dest", moving objects in reverse order.
|
||||
template<typename It1, typename It2>
|
||||
static It2 move_backward(It1 I, It1 E, It2 Dest) {
|
||||
return ::std::copy_backward(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Move the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename It1, typename It2>
|
||||
@ -356,6 +321,7 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
SmallVectorImpl(const SmallVectorImpl&) = delete;
|
||||
public:
|
||||
typedef typename SuperClass::iterator iterator;
|
||||
typedef typename SuperClass::const_iterator const_iterator;
|
||||
typedef typename SuperClass::size_type size_type;
|
||||
|
||||
protected:
|
||||
@ -459,26 +425,33 @@ public:
|
||||
append(IL);
|
||||
}
|
||||
|
||||
iterator erase(iterator I) {
|
||||
iterator erase(const_iterator CI) {
|
||||
// Just cast away constness because this is a non-const member function.
|
||||
iterator I = const_cast<iterator>(CI);
|
||||
|
||||
assert(I >= this->begin() && "Iterator to erase is out of bounds.");
|
||||
assert(I < this->end() && "Erasing at past-the-end iterator.");
|
||||
|
||||
iterator N = I;
|
||||
// Shift all elts down one.
|
||||
this->move(I+1, this->end(), I);
|
||||
std::move(I+1, this->end(), I);
|
||||
// Drop the last elt.
|
||||
this->pop_back();
|
||||
return(N);
|
||||
}
|
||||
|
||||
iterator erase(iterator S, iterator E) {
|
||||
iterator erase(const_iterator CS, const_iterator CE) {
|
||||
// Just cast away constness because this is a non-const member function.
|
||||
iterator S = const_cast<iterator>(CS);
|
||||
iterator E = const_cast<iterator>(CE);
|
||||
|
||||
assert(S >= this->begin() && "Range to erase is out of bounds.");
|
||||
assert(S <= E && "Trying to erase invalid range.");
|
||||
assert(E <= this->end() && "Trying to erase past the end.");
|
||||
|
||||
iterator N = S;
|
||||
// Shift all elts down.
|
||||
iterator I = this->move(E, this->end(), S);
|
||||
iterator I = std::move(E, this->end(), S);
|
||||
// Drop the last elts.
|
||||
this->destroy_range(I, this->end());
|
||||
this->setEnd(I);
|
||||
@ -502,7 +475,7 @@ public:
|
||||
|
||||
::new ((void*) this->end()) T(::std::move(this->back()));
|
||||
// Push everything else over.
|
||||
this->move_backward(I, this->end()-1, this->end());
|
||||
std::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
|
||||
@ -531,7 +504,7 @@ public:
|
||||
}
|
||||
::new ((void*) this->end()) T(std::move(this->back()));
|
||||
// Push everything else over.
|
||||
this->move_backward(I, this->end()-1, this->end());
|
||||
std::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
|
||||
@ -572,7 +545,7 @@ public:
|
||||
std::move_iterator<iterator>(this->end()));
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
std::move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
|
||||
std::fill_n(I, NumToInsert, Elt);
|
||||
return I;
|
||||
@ -626,7 +599,7 @@ public:
|
||||
std::move_iterator<iterator>(this->end()));
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
this->move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
std::move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
|
||||
std::copy(From, To, I);
|
||||
return I;
|
||||
@ -807,7 +780,7 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||
// Assign common elements.
|
||||
iterator NewEnd = this->begin();
|
||||
if (RHSSize)
|
||||
NewEnd = this->move(RHS.begin(), RHS.end(), NewEnd);
|
||||
NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
|
||||
|
||||
// Destroy excess elements and trim the bounds.
|
||||
this->destroy_range(NewEnd, this->end());
|
||||
@ -831,7 +804,7 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||
this->grow(RHSSize);
|
||||
} else if (CurSize) {
|
||||
// Otherwise, use assignment for the already-constructed elements.
|
||||
this->move(RHS.begin(), RHS.begin()+CurSize, this->begin());
|
||||
std::move(RHS.begin(), RHS.begin()+CurSize, this->begin());
|
||||
}
|
||||
|
||||
// Move-construct the new elements in place.
|
||||
|
@ -263,6 +263,11 @@ public:
|
||||
return *insert(ValueT(Key)).first;
|
||||
}
|
||||
|
||||
ValueT pop_back_val() {
|
||||
// Sparse does not need to be cleared, see find().
|
||||
return Dense.pop_back_val();
|
||||
}
|
||||
|
||||
/// erase - Erases an existing element identified by a valid iterator.
|
||||
///
|
||||
/// This invalidates all iterators, but erase() returns an iterator pointing
|
||||
|
@ -27,7 +27,8 @@
|
||||
#define LLVM_ADT_STATISTIC_H
|
||||
|
||||
#include "llvm/Support/Atomic.h"
|
||||
#include "llvm/Support/Valgrind.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
@ -36,77 +37,66 @@ class raw_fd_ostream;
|
||||
|
||||
class Statistic {
|
||||
public:
|
||||
const char *DebugType;
|
||||
const char *Name;
|
||||
const char *Desc;
|
||||
volatile llvm::sys::cas_flag Value;
|
||||
std::atomic<unsigned> Value;
|
||||
bool Initialized;
|
||||
|
||||
llvm::sys::cas_flag getValue() const { return Value; }
|
||||
unsigned getValue() const { return Value.load(std::memory_order_relaxed); }
|
||||
const char *getDebugType() const { return DebugType; }
|
||||
const char *getName() const { return Name; }
|
||||
const char *getDesc() const { return Desc; }
|
||||
|
||||
/// construct - This should only be called for non-global statistics.
|
||||
void construct(const char *name, const char *desc) {
|
||||
Name = name; Desc = desc;
|
||||
Value = 0; Initialized = false;
|
||||
void construct(const char *debugtype, const char *name, const char *desc) {
|
||||
DebugType = debugtype;
|
||||
Name = name;
|
||||
Desc = desc;
|
||||
Value = 0;
|
||||
Initialized = false;
|
||||
}
|
||||
|
||||
// Allow use of this class as the value itself.
|
||||
operator unsigned() const { return Value; }
|
||||
operator unsigned() const { return getValue(); }
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
|
||||
const Statistic &operator=(unsigned Val) {
|
||||
Value = Val;
|
||||
Value.store(Val, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
const Statistic &operator++() {
|
||||
// FIXME: This function and all those that follow carefully use an
|
||||
// atomic operation to update the value safely in the presence of
|
||||
// concurrent accesses, but not to read the return value, so the
|
||||
// return value is not thread safe.
|
||||
sys::AtomicIncrement(&Value);
|
||||
Value.fetch_add(1, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
unsigned operator++(int) {
|
||||
init();
|
||||
unsigned OldValue = Value;
|
||||
sys::AtomicIncrement(&Value);
|
||||
return OldValue;
|
||||
return Value.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
const Statistic &operator--() {
|
||||
sys::AtomicDecrement(&Value);
|
||||
Value.fetch_sub(1, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
unsigned operator--(int) {
|
||||
init();
|
||||
unsigned OldValue = Value;
|
||||
sys::AtomicDecrement(&Value);
|
||||
return OldValue;
|
||||
return Value.fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
const Statistic &operator+=(const unsigned &V) {
|
||||
if (!V) return *this;
|
||||
sys::AtomicAdd(&Value, V);
|
||||
const Statistic &operator+=(unsigned V) {
|
||||
if (V == 0)
|
||||
return *this;
|
||||
Value.fetch_add(V, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
const Statistic &operator-=(const unsigned &V) {
|
||||
if (!V) return *this;
|
||||
sys::AtomicAdd(&Value, -V);
|
||||
return init();
|
||||
}
|
||||
|
||||
const Statistic &operator*=(const unsigned &V) {
|
||||
sys::AtomicMul(&Value, V);
|
||||
return init();
|
||||
}
|
||||
|
||||
const Statistic &operator/=(const unsigned &V) {
|
||||
sys::AtomicDiv(&Value, V);
|
||||
const Statistic &operator-=(unsigned V) {
|
||||
if (V == 0)
|
||||
return *this;
|
||||
Value.fetch_sub(V, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
@ -140,14 +130,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Statistic &operator*=(const unsigned &V) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Statistic &operator/=(const unsigned &V) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
|
||||
|
||||
protected:
|
||||
@ -163,8 +145,8 @@ protected:
|
||||
|
||||
// STATISTIC - A macro to make definition of statistics really simple. This
|
||||
// automatically passes the DEBUG_TYPE of the file into the statistic.
|
||||
#define STATISTIC(VARNAME, DESC) \
|
||||
static llvm::Statistic VARNAME = { DEBUG_TYPE, DESC, 0, 0 }
|
||||
#define STATISTIC(VARNAME, DESC) \
|
||||
static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, 0}
|
||||
|
||||
/// \brief Enable the collection and printing of statistics.
|
||||
void EnableStatistics();
|
||||
@ -181,6 +163,9 @@ void PrintStatistics();
|
||||
/// \brief Print statistics to the given output stream.
|
||||
void PrintStatistics(raw_ostream &OS);
|
||||
|
||||
} // End llvm namespace
|
||||
/// Print statistics in JSON format.
|
||||
void PrintStatisticsJSON(raw_ostream &OS);
|
||||
|
||||
#endif
|
||||
} // end llvm namespace
|
||||
|
||||
#endif // LLVM_ADT_STATISTIC_H
|
||||
|
@ -44,55 +44,40 @@ static inline unsigned hexDigitValue(char C) {
|
||||
return -1U;
|
||||
}
|
||||
|
||||
/// utohex_buffer - Emit the specified number into the buffer specified by
|
||||
/// BufferEnd, returning a pointer to the start of the string. This can be used
|
||||
/// like this: (note that the buffer must be large enough to handle any number):
|
||||
/// char Buffer[40];
|
||||
/// printf("0x%s", utohex_buffer(X, Buffer+40));
|
||||
///
|
||||
/// This should only be used with unsigned types.
|
||||
///
|
||||
template<typename IntTy>
|
||||
static inline char *utohex_buffer(IntTy X, char *BufferEnd, bool LowerCase = false) {
|
||||
char *BufPtr = BufferEnd;
|
||||
*--BufPtr = 0; // Null terminate buffer.
|
||||
if (X == 0) {
|
||||
*--BufPtr = '0'; // Handle special case.
|
||||
return BufPtr;
|
||||
}
|
||||
static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||
char Buffer[17];
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
||||
if (X == 0) *--BufPtr = '0';
|
||||
|
||||
while (X) {
|
||||
unsigned char Mod = static_cast<unsigned char>(X) & 15;
|
||||
*--BufPtr = hexdigit(Mod, LowerCase);
|
||||
X >>= 4;
|
||||
}
|
||||
return BufPtr;
|
||||
|
||||
return std::string(BufPtr, std::end(Buffer));
|
||||
}
|
||||
|
||||
static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||
char Buffer[17];
|
||||
return utohex_buffer(X, Buffer+17, LowerCase);
|
||||
}
|
||||
/// Convert buffer \p Input to its hexadecimal representation.
|
||||
/// The returned string is double the size of \p Input.
|
||||
static inline std::string toHex(StringRef Input) {
|
||||
static const char *const LUT = "0123456789ABCDEF";
|
||||
size_t Length = Input.size();
|
||||
|
||||
static inline std::string utostr_32(uint32_t X, bool isNeg = false) {
|
||||
char Buffer[11];
|
||||
char *BufPtr = Buffer+11;
|
||||
|
||||
if (X == 0) *--BufPtr = '0'; // Handle special case...
|
||||
|
||||
while (X) {
|
||||
*--BufPtr = '0' + char(X % 10);
|
||||
X /= 10;
|
||||
std::string Output;
|
||||
Output.reserve(2 * Length);
|
||||
for (size_t i = 0; i < Length; ++i) {
|
||||
const unsigned char c = Input[i];
|
||||
Output.push_back(LUT[c >> 4]);
|
||||
Output.push_back(LUT[c & 15]);
|
||||
}
|
||||
|
||||
if (isNeg) *--BufPtr = '-'; // Add negative sign...
|
||||
|
||||
return std::string(BufPtr, Buffer+11);
|
||||
return Output;
|
||||
}
|
||||
|
||||
static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
char Buffer[21];
|
||||
char *BufPtr = Buffer+21;
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
||||
if (X == 0) *--BufPtr = '0'; // Handle special case...
|
||||
|
||||
@ -102,7 +87,7 @@ static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
}
|
||||
|
||||
if (isNeg) *--BufPtr = '-'; // Add negative sign...
|
||||
return std::string(BufPtr, Buffer+21);
|
||||
return std::string(BufPtr, std::end(Buffer));
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
@ -88,12 +89,15 @@ protected:
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *RemoveKey(StringRef Key);
|
||||
|
||||
private:
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
void init(unsigned Size);
|
||||
|
||||
public:
|
||||
static StringMapEntryBase *getTombstoneVal() {
|
||||
return (StringMapEntryBase*)-1;
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<StringMapEntryBase *>(Val);
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const { return NumBuckets; }
|
||||
@ -122,9 +126,9 @@ public:
|
||||
|
||||
explicit StringMapEntry(unsigned strLen)
|
||||
: StringMapEntryBase(strLen), second() {}
|
||||
template <class InitTy>
|
||||
StringMapEntry(unsigned strLen, InitTy &&V)
|
||||
: StringMapEntryBase(strLen), second(std::forward<InitTy>(V)) {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntry(unsigned strLen, InitTy &&... InitVals)
|
||||
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), getKeyLength());
|
||||
@ -142,11 +146,11 @@ public:
|
||||
|
||||
StringRef first() const { return StringRef(getKeyData(), getKeyLength()); }
|
||||
|
||||
/// Create - Create a StringMapEntry for the specified key and default
|
||||
/// construct the value.
|
||||
template <typename AllocatorTy, typename InitType>
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename AllocatorTy, typename... InitTy>
|
||||
static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator,
|
||||
InitType &&InitVal) {
|
||||
InitTy &&... InitVals) {
|
||||
unsigned KeyLength = Key.size();
|
||||
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
@ -158,8 +162,8 @@ public:
|
||||
StringMapEntry *NewItem =
|
||||
static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
|
||||
|
||||
// Default construct the value.
|
||||
new (NewItem) StringMapEntry(KeyLength, std::forward<InitType>(InitVal));
|
||||
// Construct the value.
|
||||
new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
|
||||
|
||||
// Copy the string information.
|
||||
char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
|
||||
@ -169,16 +173,11 @@ public:
|
||||
return NewItem;
|
||||
}
|
||||
|
||||
template<typename AllocatorTy>
|
||||
static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator) {
|
||||
return Create(Key, Allocator, ValueTy());
|
||||
}
|
||||
|
||||
/// Create - Create a StringMapEntry with normal malloc/free.
|
||||
template<typename InitType>
|
||||
static StringMapEntry *Create(StringRef Key, InitType &&InitVal) {
|
||||
template <typename... InitType>
|
||||
static StringMapEntry *Create(StringRef Key, InitType &&... InitVal) {
|
||||
MallocAllocator A;
|
||||
return Create(Key, A, std::forward<InitType>(InitVal));
|
||||
return Create(Key, A, std::forward<InitType>(InitVal)...);
|
||||
}
|
||||
|
||||
static StringMapEntry *Create(StringRef Key) {
|
||||
@ -233,7 +232,7 @@ public:
|
||||
Allocator(A) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
for (const auto &P : List) {
|
||||
insert(P);
|
||||
}
|
||||
@ -248,7 +247,40 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
// FIXME: Implement copy operations if/when they're needed.
|
||||
StringMap(const StringMap &RHS) :
|
||||
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(RHS.Allocator) {
|
||||
if (RHS.empty())
|
||||
return;
|
||||
|
||||
// Allocate TheTable of the same size as RHS's TheTable, and set the
|
||||
// sentinel appropriately (and NumBuckets).
|
||||
init(RHS.NumBuckets);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
|
||||
*RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
|
||||
|
||||
NumItems = RHS.NumItems;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = RHS.TheTable[I];
|
||||
if (!Bucket || Bucket == getTombstoneVal()) {
|
||||
TheTable[I] = Bucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
TheTable[I] = MapEntryTy::Create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
|
||||
static_cast<MapEntryTy *>(Bucket)->getValue());
|
||||
HashTable[I] = RHSHashTable[I];
|
||||
}
|
||||
|
||||
// Note that here we've copied everything from the RHS into this object,
|
||||
// tombstones included. We could, instead, have re-probed for each key to
|
||||
// instantiate this new object without any tombstone buckets. The
|
||||
// assumption here is that items are rarely deleted from most StringMaps,
|
||||
// and so tombstones are rare, so the cost of re-probing for all inputs is
|
||||
// not worthwhile.
|
||||
}
|
||||
|
||||
AllocatorTy &getAllocator() { return Allocator; }
|
||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||
@ -295,8 +327,10 @@ public:
|
||||
return ValueTy();
|
||||
}
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
ValueTy &operator[](StringRef Key) {
|
||||
return insert(std::make_pair(Key, ValueTy())).first->second;
|
||||
return emplace_second(Key).first->second;
|
||||
}
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
@ -328,7 +362,16 @@ public:
|
||||
/// 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);
|
||||
return emplace_second(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key 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.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false),
|
||||
@ -336,8 +379,7 @@ public:
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket =
|
||||
MapEntryTy::Create(KV.first, Allocator, std::move(KV.second));
|
||||
Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_ADT_STRINGREF_H
|
||||
#define LLVM_ADT_STRINGREF_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@ -101,6 +102,9 @@ namespace llvm {
|
||||
const unsigned char *bytes_end() const {
|
||||
return reinterpret_cast<const unsigned char *>(end());
|
||||
}
|
||||
iterator_range<const unsigned char *> bytes() const {
|
||||
return make_range(bytes_begin(), bytes_end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
@ -133,6 +137,9 @@ namespace llvm {
|
||||
|
||||
// copy - Allocate copy in Allocator and return StringRef to it.
|
||||
template <typename Allocator> StringRef copy(Allocator &A) const {
|
||||
// Don't request a length 0 copy from the allocator.
|
||||
if (empty())
|
||||
return StringRef();
|
||||
char *S = A.template Allocate<char>(Length);
|
||||
std::copy(begin(), end(), S);
|
||||
return StringRef(S, Length);
|
||||
@ -443,9 +450,10 @@ namespace llvm {
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param End The index following the last character to include in the
|
||||
/// substring. If this is npos, or less than \p Start, or exceeds the
|
||||
/// number of characters remaining in the string, the string suffix
|
||||
/// (starting with \p Start) will be returned.
|
||||
/// substring. If this is npos or exceeds the number of characters
|
||||
/// remaining in the string, the string suffix (starting with \p Start)
|
||||
/// will be returned. If this is less than \p Start, an empty string will
|
||||
/// be returned.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef slice(size_t Start, size_t End) const {
|
||||
Start = std::min(Start, Length);
|
||||
@ -539,18 +547,36 @@ namespace llvm {
|
||||
return std::make_pair(slice(0, Idx), slice(Idx+1, npos));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// the left removed.
|
||||
StringRef ltrim(char Char) const {
|
||||
return drop_front(std::min(Length, find_first_not_of(Char)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left removed.
|
||||
StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const {
|
||||
return drop_front(std::min(Length, find_first_not_of(Chars)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// right removed.
|
||||
StringRef rtrim(char Char) const {
|
||||
return drop_back(Length - std::min(Length, find_last_not_of(Char) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the right removed.
|
||||
StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const {
|
||||
return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// left and right removed.
|
||||
StringRef trim(char Char) const {
|
||||
return ltrim(Char).rtrim(Char);
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left and right removed.
|
||||
StringRef trim(StringRef Chars = " \t\n\v\f\r") const {
|
||||
|
@ -33,6 +33,12 @@ namespace llvm {
|
||||
assert(!Key.empty());
|
||||
return base::insert(std::make_pair(Key, '\0'));
|
||||
}
|
||||
|
||||
template <typename InputIt>
|
||||
void insert(const InputIt &Begin, const InputIt &End) {
|
||||
for (auto It = Begin; It != End; ++It)
|
||||
base::insert(std::make_pair(*It, '\0'));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,16 @@ public:
|
||||
/// This also is a constructor for individual array elements due to the single
|
||||
/// element constructor for ArrayRef.
|
||||
explicit TinyPtrVector(ArrayRef<EltTy> Elts)
|
||||
: Val(Elts.size() == 1 ? PtrUnion(Elts[0])
|
||||
: PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {}
|
||||
: Val(Elts.empty()
|
||||
? PtrUnion()
|
||||
: Elts.size() == 1
|
||||
? PtrUnion(Elts[0])
|
||||
: PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {}
|
||||
|
||||
TinyPtrVector(size_t Count, EltTy Value)
|
||||
: Val(Count == 0 ? PtrUnion()
|
||||
: Count == 1 ? PtrUnion(Value)
|
||||
: PtrUnion(new VecTy(Count, Value))) {}
|
||||
|
||||
// implicit conversion operator to ArrayRef.
|
||||
operator ArrayRef<EltTy>() const {
|
||||
@ -125,6 +133,15 @@ public:
|
||||
return *Val.template get<VecTy*>();
|
||||
}
|
||||
|
||||
// Implicit conversion to ArrayRef<U> if EltTy* implicitly converts to U*.
|
||||
template<typename U,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ArrayRef<EltTy>, ArrayRef<U>>::value,
|
||||
bool>::type = false>
|
||||
operator ArrayRef<U>() const {
|
||||
return operator ArrayRef<EltTy>();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
// This vector can be empty if it contains no element, or if it
|
||||
// contains a pointer to an empty vector.
|
||||
@ -142,8 +159,10 @@ public:
|
||||
return Val.template get<VecTy*>()->size();
|
||||
}
|
||||
|
||||
typedef const EltTy *const_iterator;
|
||||
typedef EltTy *iterator;
|
||||
typedef const EltTy *const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
iterator begin() {
|
||||
if (Val.template is<EltTy>())
|
||||
@ -166,6 +185,15 @@ public:
|
||||
return (const_iterator)const_cast<TinyPtrVector*>(this)->end();
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
EltTy operator[](unsigned i) const {
|
||||
assert(!Val.isNull() && "can't index into an empty vector");
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||
|
@ -46,49 +46,52 @@ public:
|
||||
enum ArchType {
|
||||
UnknownArch,
|
||||
|
||||
arm, // ARM (little endian): arm, armv.*, xscale
|
||||
armeb, // ARM (big endian): armeb
|
||||
aarch64, // AArch64 (little endian): aarch64
|
||||
aarch64_be, // AArch64 (big endian): aarch64_be
|
||||
avr, // AVR: Atmel AVR microcontroller
|
||||
bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
|
||||
bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
mips64, // MIPS64: mips64
|
||||
mips64el, // MIPS64EL: mips64el
|
||||
msp430, // MSP430: msp430
|
||||
ppc, // PPC: powerpc
|
||||
ppc64, // PPC64: powerpc64, ppu
|
||||
ppc64le, // PPC64LE: powerpc64le
|
||||
r600, // R600: AMD GPUs HD2XXX - HD6XXX
|
||||
amdgcn, // AMDGCN: AMD GCN GPUs
|
||||
sparc, // Sparc: sparc
|
||||
sparcv9, // Sparcv9: Sparcv9
|
||||
sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
|
||||
systemz, // SystemZ: s390x
|
||||
tce, // TCE (http://tce.cs.tut.fi/): tce
|
||||
thumb, // Thumb (little endian): thumb, thumbv.*
|
||||
thumbeb, // Thumb (big endian): thumbeb
|
||||
x86, // X86: i[3-9]86
|
||||
x86_64, // X86-64: amd64, x86_64
|
||||
xcore, // XCore: xcore
|
||||
nvptx, // NVPTX: 32-bit
|
||||
nvptx64, // NVPTX: 64-bit
|
||||
le32, // le32: generic little-endian 32-bit CPU (PNaCl)
|
||||
le64, // le64: generic little-endian 64-bit CPU (PNaCl)
|
||||
amdil, // AMDIL
|
||||
amdil64, // AMDIL with 64-bit pointers
|
||||
hsail, // AMD HSAIL
|
||||
hsail64, // AMD HSAIL with 64-bit pointers
|
||||
spir, // SPIR: standard portable IR for OpenCL 32-bit version
|
||||
spir64, // SPIR: standard portable IR for OpenCL 64-bit version
|
||||
kalimba, // Kalimba: generic kalimba
|
||||
shave, // SHAVE: Movidius vector VLIW processors
|
||||
wasm32, // WebAssembly with 32-bit pointers
|
||||
wasm64, // WebAssembly with 64-bit pointers
|
||||
LastArchType = wasm64
|
||||
arm, // ARM (little endian): arm, armv.*, xscale
|
||||
armeb, // ARM (big endian): armeb
|
||||
aarch64, // AArch64 (little endian): aarch64
|
||||
aarch64_be, // AArch64 (big endian): aarch64_be
|
||||
avr, // AVR: Atmel AVR microcontroller
|
||||
bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
|
||||
bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
mips64, // MIPS64: mips64
|
||||
mips64el, // MIPS64EL: mips64el
|
||||
msp430, // MSP430: msp430
|
||||
ppc, // PPC: powerpc
|
||||
ppc64, // PPC64: powerpc64, ppu
|
||||
ppc64le, // PPC64LE: powerpc64le
|
||||
r600, // R600: AMD GPUs HD2XXX - HD6XXX
|
||||
amdgcn, // AMDGCN: AMD GCN GPUs
|
||||
sparc, // Sparc: sparc
|
||||
sparcv9, // Sparcv9: Sparcv9
|
||||
sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
|
||||
systemz, // SystemZ: s390x
|
||||
tce, // TCE (http://tce.cs.tut.fi/): tce
|
||||
thumb, // Thumb (little endian): thumb, thumbv.*
|
||||
thumbeb, // Thumb (big endian): thumbeb
|
||||
x86, // X86: i[3-9]86
|
||||
x86_64, // X86-64: amd64, x86_64
|
||||
xcore, // XCore: xcore
|
||||
nvptx, // NVPTX: 32-bit
|
||||
nvptx64, // NVPTX: 64-bit
|
||||
le32, // le32: generic little-endian 32-bit CPU (PNaCl)
|
||||
le64, // le64: generic little-endian 64-bit CPU (PNaCl)
|
||||
amdil, // AMDIL
|
||||
amdil64, // AMDIL with 64-bit pointers
|
||||
hsail, // AMD HSAIL
|
||||
hsail64, // AMD HSAIL with 64-bit pointers
|
||||
spir, // SPIR: standard portable IR for OpenCL 32-bit version
|
||||
spir64, // SPIR: standard portable IR for OpenCL 64-bit version
|
||||
kalimba, // Kalimba: generic kalimba
|
||||
shave, // SHAVE: Movidius vector VLIW processors
|
||||
lanai, // Lanai: Lanai 32-bit
|
||||
wasm32, // WebAssembly with 32-bit pointers
|
||||
wasm64, // WebAssembly with 64-bit pointers
|
||||
renderscript32, // 32-bit RenderScript
|
||||
renderscript64, // 64-bit RenderScript
|
||||
LastArchType = renderscript64
|
||||
};
|
||||
enum SubArchType {
|
||||
NoSubArch,
|
||||
@ -96,6 +99,8 @@ public:
|
||||
ARMSubArch_v8_2a,
|
||||
ARMSubArch_v8_1a,
|
||||
ARMSubArch_v8,
|
||||
ARMSubArch_v8m_baseline,
|
||||
ARMSubArch_v8m_mainline,
|
||||
ARMSubArch_v7,
|
||||
ARMSubArch_v7em,
|
||||
ARMSubArch_v7m,
|
||||
@ -128,7 +133,9 @@ public:
|
||||
NVIDIA,
|
||||
CSR,
|
||||
Myriad,
|
||||
LastVendorType = Myriad
|
||||
AMD,
|
||||
Mesa,
|
||||
LastVendorType = Mesa
|
||||
};
|
||||
enum OSType {
|
||||
UnknownOS,
|
||||
@ -160,7 +167,8 @@ public:
|
||||
ELFIAMCU,
|
||||
TvOS, // Apple tvOS
|
||||
WatchOS, // Apple watchOS
|
||||
LastOSType = WatchOS
|
||||
Mesa3D,
|
||||
LastOSType = Mesa3D
|
||||
};
|
||||
enum EnvironmentType {
|
||||
UnknownEnvironment,
|
||||
@ -173,6 +181,9 @@ public:
|
||||
EABI,
|
||||
EABIHF,
|
||||
Android,
|
||||
Musl,
|
||||
MuslEABI,
|
||||
MuslEABIHF,
|
||||
|
||||
MSVC,
|
||||
Itanium,
|
||||
@ -390,8 +401,8 @@ public:
|
||||
/// isMacOSXVersionLT - Comparison function for checking OS X version
|
||||
/// compatibility, which handles supporting skewed version numbering schemes
|
||||
/// used by the "darwin" triples.
|
||||
unsigned isMacOSXVersionLT(unsigned Major, unsigned Minor = 0,
|
||||
unsigned Micro = 0) const {
|
||||
bool isMacOSXVersionLT(unsigned Major, unsigned Minor = 0,
|
||||
unsigned Micro = 0) const {
|
||||
assert(isMacOSX() && "Not an OS X triple!");
|
||||
|
||||
// If this is OS X, expect a sane version number.
|
||||
@ -428,6 +439,10 @@ public:
|
||||
return getOS() == Triple::WatchOS;
|
||||
}
|
||||
|
||||
bool isWatchABI() const {
|
||||
return getSubArch() == Triple::ARMSubArch_v7k;
|
||||
}
|
||||
|
||||
/// isOSDarwin - Is this a "Darwin" OS (OS X, iOS, or watchOS).
|
||||
bool isOSDarwin() const {
|
||||
return isMacOSX() || isiOS() || isWatchOS();
|
||||
@ -459,6 +474,12 @@ public:
|
||||
return getOS() == Triple::ELFIAMCU;
|
||||
}
|
||||
|
||||
bool isGNUEnvironment() const {
|
||||
EnvironmentType Env = getEnvironment();
|
||||
return Env == Triple::GNU || Env == Triple::GNUEABI ||
|
||||
Env == Triple::GNUEABIHF || Env == Triple::GNUX32;
|
||||
}
|
||||
|
||||
/// Checks if the environment could be MSVC.
|
||||
bool isWindowsMSVCEnvironment() const {
|
||||
return getOS() == Triple::Win32 &&
|
||||
@ -513,6 +534,16 @@ public:
|
||||
return getOS() == Triple::Linux;
|
||||
}
|
||||
|
||||
/// Tests whether the OS is kFreeBSD.
|
||||
bool isOSKFreeBSD() const {
|
||||
return getOS() == Triple::KFreeBSD;
|
||||
}
|
||||
|
||||
/// Tests whether the OS uses glibc.
|
||||
bool isOSGlibc() const {
|
||||
return getOS() == Triple::Linux || getOS() == Triple::KFreeBSD;
|
||||
}
|
||||
|
||||
/// Tests whether the OS uses the ELF binary format.
|
||||
bool isOSBinFormatELF() const {
|
||||
return getObjectFormat() == Triple::ELF;
|
||||
@ -544,6 +575,21 @@ public:
|
||||
/// Tests whether the target is Android
|
||||
bool isAndroid() const { return getEnvironment() == Triple::Android; }
|
||||
|
||||
/// Tests whether the environment is musl-libc
|
||||
bool isMusl() const {
|
||||
return getEnvironment() == Triple::Musl ||
|
||||
getEnvironment() == Triple::MuslEABI ||
|
||||
getEnvironment() == Triple::MuslEABIHF;
|
||||
}
|
||||
|
||||
/// Tests whether the target is NVPTX (32- or 64-bit).
|
||||
bool isNVPTX() const {
|
||||
return getArch() == Triple::nvptx || getArch() == Triple::nvptx64;
|
||||
}
|
||||
|
||||
/// Tests wether the target supports comdat
|
||||
bool supportsCOMDAT() const { return !isOSBinFormatMachO(); }
|
||||
|
||||
/// @}
|
||||
/// @name Mutators
|
||||
/// @{
|
||||
@ -632,6 +678,11 @@ public:
|
||||
/// string then the triple's arch name is used.
|
||||
StringRef getARMCPUForArch(StringRef Arch = StringRef()) const;
|
||||
|
||||
/// Tests whether the target triple is little endian.
|
||||
///
|
||||
/// \returns true if the triple is little endian, false otherwise.
|
||||
bool isLittleEndian() const;
|
||||
|
||||
/// @}
|
||||
/// @name Static helpers for IDs.
|
||||
/// @{
|
||||
|
@ -186,53 +186,38 @@ template<typename Ty>
|
||||
struct ilist_traits<const Ty> : public ilist_traits<Ty> {};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ilist_iterator<Node> - Iterator for intrusive list.
|
||||
// Iterator for intrusive list.
|
||||
//
|
||||
template<typename NodeTy>
|
||||
template <typename NodeTy>
|
||||
class ilist_iterator
|
||||
: public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> {
|
||||
|
||||
: public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> {
|
||||
public:
|
||||
typedef ilist_traits<NodeTy> Traits;
|
||||
typedef std::iterator<std::bidirectional_iterator_tag,
|
||||
NodeTy, ptrdiff_t> super;
|
||||
typedef std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t>
|
||||
super;
|
||||
|
||||
typedef typename super::value_type value_type;
|
||||
typedef typename super::difference_type difference_type;
|
||||
typedef typename super::pointer pointer;
|
||||
typedef typename super::reference reference;
|
||||
|
||||
private:
|
||||
pointer NodePtr;
|
||||
|
||||
// ilist_iterator is not a random-access iterator, but it has an
|
||||
// implicit conversion to pointer-type, which is. Declare (but
|
||||
// don't define) these functions as private to help catch
|
||||
// accidental misuse.
|
||||
void operator[](difference_type) const;
|
||||
void operator+(difference_type) const;
|
||||
void operator-(difference_type) const;
|
||||
void operator+=(difference_type) const;
|
||||
void operator-=(difference_type) const;
|
||||
template<class T> void operator<(T) const;
|
||||
template<class T> void operator<=(T) const;
|
||||
template<class T> void operator>(T) const;
|
||||
template<class T> void operator>=(T) const;
|
||||
template<class T> void operator-(T) const;
|
||||
public:
|
||||
|
||||
explicit ilist_iterator(pointer NP) : NodePtr(NP) {}
|
||||
explicit ilist_iterator(reference NR) : NodePtr(&NR) {}
|
||||
ilist_iterator() : NodePtr(nullptr) {}
|
||||
|
||||
// This is templated so that we can allow constructing a const iterator from
|
||||
// a nonconst iterator...
|
||||
template<class node_ty>
|
||||
template <class node_ty>
|
||||
ilist_iterator(const ilist_iterator<node_ty> &RHS)
|
||||
: NodePtr(RHS.getNodePtrUnchecked()) {}
|
||||
: NodePtr(RHS.getNodePtrUnchecked()) {}
|
||||
|
||||
// This is templated so that we can allow assigning to a const iterator from
|
||||
// a nonconst iterator...
|
||||
template<class node_ty>
|
||||
template <class node_ty>
|
||||
const ilist_iterator &operator=(const ilist_iterator<node_ty> &RHS) {
|
||||
NodePtr = RHS.getNodePtrUnchecked();
|
||||
return *this;
|
||||
@ -241,13 +226,8 @@ public:
|
||||
void reset(pointer NP) { NodePtr = NP; }
|
||||
|
||||
// Accessors...
|
||||
explicit operator pointer() const {
|
||||
return NodePtr;
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
return *NodePtr;
|
||||
}
|
||||
explicit operator pointer() const { return NodePtr; }
|
||||
reference operator*() const { return *NodePtr; }
|
||||
pointer operator->() const { return &operator*(); }
|
||||
|
||||
// Comparison operators
|
||||
@ -259,21 +239,21 @@ public:
|
||||
}
|
||||
|
||||
// Increment and decrement operators...
|
||||
ilist_iterator &operator--() { // predecrement - Back up
|
||||
ilist_iterator &operator--() {
|
||||
NodePtr = Traits::getPrev(NodePtr);
|
||||
assert(NodePtr && "--'d off the beginning of an ilist!");
|
||||
return *this;
|
||||
}
|
||||
ilist_iterator &operator++() { // preincrement - Advance
|
||||
ilist_iterator &operator++() {
|
||||
NodePtr = Traits::getNext(NodePtr);
|
||||
return *this;
|
||||
}
|
||||
ilist_iterator operator--(int) { // postdecrement operators...
|
||||
ilist_iterator operator--(int) {
|
||||
ilist_iterator tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
ilist_iterator operator++(int) { // postincrement operators...
|
||||
ilist_iterator operator++(int) {
|
||||
ilist_iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
@ -283,38 +263,6 @@ public:
|
||||
pointer getNodePtrUnchecked() const { return NodePtr; }
|
||||
};
|
||||
|
||||
// These are to catch errors when people try to use them as random access
|
||||
// iterators.
|
||||
template<typename T>
|
||||
void operator-(int, ilist_iterator<T>) = delete;
|
||||
template<typename T>
|
||||
void operator-(ilist_iterator<T>,int) = delete;
|
||||
|
||||
template<typename T>
|
||||
void operator+(int, ilist_iterator<T>) = delete;
|
||||
template<typename T>
|
||||
void operator+(ilist_iterator<T>,int) = delete;
|
||||
|
||||
// operator!=/operator== - Allow mixed comparisons without dereferencing
|
||||
// the iterator, which could very likely be pointing to end().
|
||||
template<typename T>
|
||||
bool operator!=(const T* LHS, const ilist_iterator<const T> &RHS) {
|
||||
return LHS != RHS.getNodePtrUnchecked();
|
||||
}
|
||||
template<typename T>
|
||||
bool operator==(const T* LHS, const ilist_iterator<const T> &RHS) {
|
||||
return LHS == RHS.getNodePtrUnchecked();
|
||||
}
|
||||
template<typename T>
|
||||
bool operator!=(T* LHS, const ilist_iterator<T> &RHS) {
|
||||
return LHS != RHS.getNodePtrUnchecked();
|
||||
}
|
||||
template<typename T>
|
||||
bool operator==(T* LHS, const ilist_iterator<T> &RHS) {
|
||||
return LHS == RHS.getNodePtrUnchecked();
|
||||
}
|
||||
|
||||
|
||||
// Allow ilist_iterators to convert into pointers to a node automatically when
|
||||
// used by the dyn_cast, cast, isa mechanisms...
|
||||
|
||||
@ -474,6 +422,10 @@ public:
|
||||
return iterator(New);
|
||||
}
|
||||
|
||||
iterator insert(iterator where, const NodeTy &New) {
|
||||
return this->insert(where, new NodeTy(New));
|
||||
}
|
||||
|
||||
iterator insertAfter(iterator where, NodeTy *New) {
|
||||
if (empty())
|
||||
return insert(begin(), New);
|
||||
@ -720,7 +672,7 @@ struct ilist : public iplist<NodeTy> {
|
||||
typedef typename iplist<NodeTy>::iterator iterator;
|
||||
|
||||
ilist() {}
|
||||
ilist(const ilist &right) {
|
||||
ilist(const ilist &right) : iplist<NodeTy>() {
|
||||
insert(this->begin(), right.begin(), right.end());
|
||||
}
|
||||
explicit ilist(size_type count) {
|
||||
|
@ -46,6 +46,22 @@ protected:
|
||||
std::is_base_of<std::bidirectional_iterator_tag, IteratorCategoryT>::value,
|
||||
};
|
||||
|
||||
/// A proxy object for computing a reference via indirecting a copy of an
|
||||
/// iterator. This is used in APIs which need to produce a reference via
|
||||
/// indirection but for which the iterator object might be a temporary. The
|
||||
/// proxy preserves the iterator internally and exposes the indirected
|
||||
/// reference via a conversion operator.
|
||||
class ReferenceProxy {
|
||||
friend iterator_facade_base;
|
||||
|
||||
DerivedT I;
|
||||
|
||||
ReferenceProxy(DerivedT I) : I(std::move(I)) {}
|
||||
|
||||
public:
|
||||
operator ReferenceT() const { return *I; }
|
||||
};
|
||||
|
||||
public:
|
||||
DerivedT operator+(DifferenceTypeT n) const {
|
||||
static_assert(
|
||||
@ -120,10 +136,10 @@ public:
|
||||
PointerT operator->() const {
|
||||
return &static_cast<const DerivedT *>(this)->operator*();
|
||||
}
|
||||
ReferenceT operator[](DifferenceTypeT n) const {
|
||||
ReferenceProxy operator[](DifferenceTypeT n) const {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return *static_cast<const DerivedT *>(this)->operator+(n);
|
||||
return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,11 +38,11 @@
|
||||
#ifndef LLVM_ANALYSIS_ALIASANALYSIS_H
|
||||
#define LLVM_ANALYSIS_ALIASANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Analysis/MemoryLocation.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class BasicAAResult;
|
||||
@ -50,7 +50,6 @@ class LoadInst;
|
||||
class StoreInst;
|
||||
class VAArgInst;
|
||||
class DataLayout;
|
||||
class TargetLibraryInfo;
|
||||
class Pass;
|
||||
class AnalysisUsage;
|
||||
class MemTransferInst;
|
||||
@ -141,7 +140,7 @@ enum FunctionModRefBehavior {
|
||||
/// non-volatile loads and stores from objects pointed to by its
|
||||
/// pointer-typed arguments, with arbitrary offsets.
|
||||
///
|
||||
/// This property corresponds to the IntrReadWriteArgMem LLVM intrinsic flag.
|
||||
/// This property corresponds to the IntrArgMemOnly LLVM intrinsic flag.
|
||||
FMRB_OnlyAccessesArgumentPointees = FMRL_ArgumentPointees | MRI_ModRef,
|
||||
|
||||
/// This function does not perform any non-local stores or volatile loads,
|
||||
@ -152,6 +151,13 @@ enum FunctionModRefBehavior {
|
||||
/// This property corresponds to the IntrReadMem LLVM intrinsic flag.
|
||||
FMRB_OnlyReadsMemory = FMRL_Anywhere | MRI_Ref,
|
||||
|
||||
// This function does not read from memory anywhere, but may write to any
|
||||
// memory location.
|
||||
//
|
||||
// This property corresponds to the LLVM IR 'writeonly' attribute.
|
||||
// This property corresponds to the IntrWriteMem LLVM intrinsic flag.
|
||||
FMRB_DoesNotReadMemory = FMRL_Anywhere | MRI_Mod,
|
||||
|
||||
/// This indicates that the function could not be classified into one of the
|
||||
/// behaviors above.
|
||||
FMRB_UnknownModRefBehavior = FMRL_Anywhere | MRI_ModRef
|
||||
@ -161,9 +167,8 @@ class AAResults {
|
||||
public:
|
||||
// Make these results default constructable and movable. We have to spell
|
||||
// these out because MSVC won't synthesize them.
|
||||
AAResults() {}
|
||||
AAResults(const TargetLibraryInfo &TLI) : TLI(TLI) {}
|
||||
AAResults(AAResults &&Arg);
|
||||
AAResults &operator=(AAResults &&Arg);
|
||||
~AAResults();
|
||||
|
||||
/// Register a specific AA result.
|
||||
@ -314,6 +319,12 @@ public:
|
||||
return !(MRB & MRI_Mod);
|
||||
}
|
||||
|
||||
/// Checks if functions with the specified behavior are known to only write
|
||||
/// memory (or not access memory at all).
|
||||
static bool doesNotReadMemory(FunctionModRefBehavior MRB) {
|
||||
return !(MRB & MRI_Ref);
|
||||
}
|
||||
|
||||
/// Checks if functions with the specified behavior are known to read and
|
||||
/// write at most from objects pointed to by their pointer-typed arguments
|
||||
/// (with arbitrary offsets).
|
||||
@ -450,11 +461,11 @@ public:
|
||||
ModRefInfo getModRefInfo(const Instruction *I) {
|
||||
if (auto CS = ImmutableCallSite(I)) {
|
||||
auto MRB = getModRefBehavior(CS);
|
||||
if (MRB & MRI_ModRef)
|
||||
if ((MRB & MRI_ModRef) == MRI_ModRef)
|
||||
return MRI_ModRef;
|
||||
else if (MRB & MRI_Ref)
|
||||
if (MRB & MRI_Ref)
|
||||
return MRI_Ref;
|
||||
else if (MRB & MRI_Mod)
|
||||
if (MRB & MRI_Mod)
|
||||
return MRI_Mod;
|
||||
return MRI_NoModRef;
|
||||
}
|
||||
@ -557,6 +568,8 @@ private:
|
||||
|
||||
template <typename T> friend class AAResultBase;
|
||||
|
||||
const TargetLibraryInfo &TLI;
|
||||
|
||||
std::vector<std::unique_ptr<Concept>> AAs;
|
||||
};
|
||||
|
||||
@ -753,20 +766,23 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
const TargetLibraryInfo &TLI;
|
||||
|
||||
explicit AAResultBase(const TargetLibraryInfo &TLI) : TLI(TLI) {}
|
||||
explicit AAResultBase() {}
|
||||
|
||||
// Provide all the copy and move constructors so that derived types aren't
|
||||
// constrained.
|
||||
AAResultBase(const AAResultBase &Arg) : TLI(Arg.TLI) {}
|
||||
AAResultBase(AAResultBase &&Arg) : TLI(Arg.TLI) {}
|
||||
AAResultBase(const AAResultBase &Arg) {}
|
||||
AAResultBase(AAResultBase &&Arg) {}
|
||||
|
||||
/// Get a proxy for the best AA result set to query at this time.
|
||||
///
|
||||
/// When this result is part of a larger aggregation, this will proxy to that
|
||||
/// aggregation. When this result is used in isolation, it will just delegate
|
||||
/// back to the derived class's implementation.
|
||||
///
|
||||
/// Note that callers of this need to take considerable care to not cause
|
||||
/// performance problems when they use this routine, in the case of a large
|
||||
/// number of alias analyses being aggregated, it can be expensive to walk
|
||||
/// back across the chain.
|
||||
AAResultsProxy getBestAAResults() { return AAResultsProxy(AAR, derived()); }
|
||||
|
||||
public:
|
||||
@ -783,13 +799,6 @@ public:
|
||||
}
|
||||
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) {
|
||||
if (!CS.hasOperandBundles())
|
||||
// If CS has operand bundles then aliasing attributes from the function it
|
||||
// calls do not directly apply to the CallSite. This can be made more
|
||||
// precise in the future.
|
||||
if (const Function *F = CS.getCalledFunction())
|
||||
return getBestAAResults().getModRefBehavior(F);
|
||||
|
||||
return FMRB_UnknownModRefBehavior;
|
||||
}
|
||||
|
||||
@ -797,170 +806,24 @@ public:
|
||||
return FMRB_UnknownModRefBehavior;
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc) {
|
||||
return MRI_ModRef;
|
||||
}
|
||||
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2);
|
||||
ModRefInfo getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) {
|
||||
return MRI_ModRef;
|
||||
}
|
||||
};
|
||||
|
||||
/// Synthesize \c ModRefInfo for a call site and memory location by examining
|
||||
/// the general behavior of the call site and any specific information for its
|
||||
/// arguments.
|
||||
///
|
||||
/// This essentially, delegates across the alias analysis interface to collect
|
||||
/// information which may be enough to (conservatively) fulfill the query.
|
||||
template <typename DerivedT>
|
||||
ModRefInfo AAResultBase<DerivedT>::getModRefInfo(ImmutableCallSite CS,
|
||||
const MemoryLocation &Loc) {
|
||||
auto MRB = getBestAAResults().getModRefBehavior(CS);
|
||||
if (MRB == FMRB_DoesNotAccessMemory)
|
||||
return MRI_NoModRef;
|
||||
|
||||
ModRefInfo Mask = MRI_ModRef;
|
||||
if (AAResults::onlyReadsMemory(MRB))
|
||||
Mask = MRI_Ref;
|
||||
|
||||
if (AAResults::onlyAccessesArgPointees(MRB)) {
|
||||
bool DoesAlias = false;
|
||||
ModRefInfo AllArgsMask = MRI_NoModRef;
|
||||
if (AAResults::doesAccessArgPointees(MRB)) {
|
||||
for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(),
|
||||
AE = CS.arg_end();
|
||||
AI != AE; ++AI) {
|
||||
const Value *Arg = *AI;
|
||||
if (!Arg->getType()->isPointerTy())
|
||||
continue;
|
||||
unsigned ArgIdx = std::distance(CS.arg_begin(), AI);
|
||||
MemoryLocation ArgLoc = MemoryLocation::getForArgument(CS, ArgIdx, TLI);
|
||||
AliasResult ArgAlias = getBestAAResults().alias(ArgLoc, Loc);
|
||||
if (ArgAlias != NoAlias) {
|
||||
ModRefInfo ArgMask = getBestAAResults().getArgModRefInfo(CS, ArgIdx);
|
||||
DoesAlias = true;
|
||||
AllArgsMask = ModRefInfo(AllArgsMask | ArgMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!DoesAlias)
|
||||
return MRI_NoModRef;
|
||||
Mask = ModRefInfo(Mask & AllArgsMask);
|
||||
}
|
||||
|
||||
// If Loc is a constant memory location, the call definitely could not
|
||||
// modify the memory location.
|
||||
if ((Mask & MRI_Mod) &&
|
||||
getBestAAResults().pointsToConstantMemory(Loc, /*OrLocal*/ false))
|
||||
Mask = ModRefInfo(Mask & ~MRI_Mod);
|
||||
|
||||
return Mask;
|
||||
}
|
||||
|
||||
/// Synthesize \c ModRefInfo for two call sites by examining the general
|
||||
/// behavior of the call site and any specific information for its arguments.
|
||||
///
|
||||
/// This essentially, delegates across the alias analysis interface to collect
|
||||
/// information which may be enough to (conservatively) fulfill the query.
|
||||
template <typename DerivedT>
|
||||
ModRefInfo AAResultBase<DerivedT>::getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2) {
|
||||
// If CS1 or CS2 are readnone, they don't interact.
|
||||
auto CS1B = getBestAAResults().getModRefBehavior(CS1);
|
||||
if (CS1B == FMRB_DoesNotAccessMemory)
|
||||
return MRI_NoModRef;
|
||||
|
||||
auto CS2B = getBestAAResults().getModRefBehavior(CS2);
|
||||
if (CS2B == FMRB_DoesNotAccessMemory)
|
||||
return MRI_NoModRef;
|
||||
|
||||
// If they both only read from memory, there is no dependence.
|
||||
if (AAResults::onlyReadsMemory(CS1B) && AAResults::onlyReadsMemory(CS2B))
|
||||
return MRI_NoModRef;
|
||||
|
||||
ModRefInfo Mask = MRI_ModRef;
|
||||
|
||||
// If CS1 only reads memory, the only dependence on CS2 can be
|
||||
// from CS1 reading memory written by CS2.
|
||||
if (AAResults::onlyReadsMemory(CS1B))
|
||||
Mask = ModRefInfo(Mask & MRI_Ref);
|
||||
|
||||
// If CS2 only access memory through arguments, accumulate the mod/ref
|
||||
// information from CS1's references to the memory referenced by
|
||||
// CS2's arguments.
|
||||
if (AAResults::onlyAccessesArgPointees(CS2B)) {
|
||||
ModRefInfo R = MRI_NoModRef;
|
||||
if (AAResults::doesAccessArgPointees(CS2B)) {
|
||||
for (ImmutableCallSite::arg_iterator I = CS2.arg_begin(),
|
||||
E = CS2.arg_end();
|
||||
I != E; ++I) {
|
||||
const Value *Arg = *I;
|
||||
if (!Arg->getType()->isPointerTy())
|
||||
continue;
|
||||
unsigned CS2ArgIdx = std::distance(CS2.arg_begin(), I);
|
||||
auto CS2ArgLoc = MemoryLocation::getForArgument(CS2, CS2ArgIdx, TLI);
|
||||
|
||||
// ArgMask indicates what CS2 might do to CS2ArgLoc, and the dependence
|
||||
// of CS1 on that location is the inverse.
|
||||
ModRefInfo ArgMask =
|
||||
getBestAAResults().getArgModRefInfo(CS2, CS2ArgIdx);
|
||||
if (ArgMask == MRI_Mod)
|
||||
ArgMask = MRI_ModRef;
|
||||
else if (ArgMask == MRI_Ref)
|
||||
ArgMask = MRI_Mod;
|
||||
|
||||
ArgMask = ModRefInfo(ArgMask &
|
||||
getBestAAResults().getModRefInfo(CS1, CS2ArgLoc));
|
||||
|
||||
R = ModRefInfo((R | ArgMask) & Mask);
|
||||
if (R == Mask)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
// If CS1 only accesses memory through arguments, check if CS2 references
|
||||
// any of the memory referenced by CS1's arguments. If not, return NoModRef.
|
||||
if (AAResults::onlyAccessesArgPointees(CS1B)) {
|
||||
ModRefInfo R = MRI_NoModRef;
|
||||
if (AAResults::doesAccessArgPointees(CS1B)) {
|
||||
for (ImmutableCallSite::arg_iterator I = CS1.arg_begin(),
|
||||
E = CS1.arg_end();
|
||||
I != E; ++I) {
|
||||
const Value *Arg = *I;
|
||||
if (!Arg->getType()->isPointerTy())
|
||||
continue;
|
||||
unsigned CS1ArgIdx = std::distance(CS1.arg_begin(), I);
|
||||
auto CS1ArgLoc = MemoryLocation::getForArgument(CS1, CS1ArgIdx, TLI);
|
||||
|
||||
// ArgMask indicates what CS1 might do to CS1ArgLoc; if CS1 might Mod
|
||||
// CS1ArgLoc, then we care about either a Mod or a Ref by CS2. If CS1
|
||||
// might Ref, then we care only about a Mod by CS2.
|
||||
ModRefInfo ArgMask = getBestAAResults().getArgModRefInfo(CS1, CS1ArgIdx);
|
||||
ModRefInfo ArgR = getBestAAResults().getModRefInfo(CS2, CS1ArgLoc);
|
||||
if (((ArgMask & MRI_Mod) != MRI_NoModRef &&
|
||||
(ArgR & MRI_ModRef) != MRI_NoModRef) ||
|
||||
((ArgMask & MRI_Ref) != MRI_NoModRef &&
|
||||
(ArgR & MRI_Mod) != MRI_NoModRef))
|
||||
R = ModRefInfo((R | ArgMask) & Mask);
|
||||
|
||||
if (R == Mask)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
return Mask;
|
||||
}
|
||||
|
||||
/// isNoAliasCall - Return true if this pointer is returned by a noalias
|
||||
/// function.
|
||||
/// Return true if this pointer is returned by a noalias function.
|
||||
bool isNoAliasCall(const Value *V);
|
||||
|
||||
/// isNoAliasArgument - Return true if this is an argument with the noalias
|
||||
/// attribute.
|
||||
/// Return true if this is an argument with the noalias attribute.
|
||||
bool isNoAliasArgument(const Value *V);
|
||||
|
||||
/// isIdentifiedObject - Return true if this pointer refers to a distinct and
|
||||
/// identifiable object. This returns true for:
|
||||
/// Return true if this pointer refers to a distinct and identifiable object.
|
||||
/// This returns true for:
|
||||
/// Global Variables and Functions (but not Global Aliases)
|
||||
/// Allocas
|
||||
/// ByVal and NoAlias Arguments
|
||||
@ -968,8 +831,8 @@ bool isNoAliasArgument(const Value *V);
|
||||
///
|
||||
bool isIdentifiedObject(const Value *V);
|
||||
|
||||
/// isIdentifiedFunctionLocal - Return true if V is umabigously identified
|
||||
/// at the function-level. Different IdentifiedFunctionLocals can't alias.
|
||||
/// 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.
|
||||
@ -987,42 +850,48 @@ bool isIdentifiedFunctionLocal(const Value *V);
|
||||
/// This manager effectively wraps the AnalysisManager for registering alias
|
||||
/// analyses. When you register your alias analysis with this manager, it will
|
||||
/// ensure the analysis itself is registered with its AnalysisManager.
|
||||
class AAManager {
|
||||
class AAManager : public AnalysisInfoMixin<AAManager> {
|
||||
public:
|
||||
typedef AAResults Result;
|
||||
|
||||
// This type hase value semantics. We have to spell these out because MSVC
|
||||
// won't synthesize them.
|
||||
AAManager() {}
|
||||
AAManager(AAManager &&Arg)
|
||||
: FunctionResultGetters(std::move(Arg.FunctionResultGetters)) {}
|
||||
AAManager(const AAManager &Arg)
|
||||
: FunctionResultGetters(Arg.FunctionResultGetters) {}
|
||||
AAManager(AAManager &&Arg) : ResultGetters(std::move(Arg.ResultGetters)) {}
|
||||
AAManager(const AAManager &Arg) : ResultGetters(Arg.ResultGetters) {}
|
||||
AAManager &operator=(AAManager &&RHS) {
|
||||
FunctionResultGetters = std::move(RHS.FunctionResultGetters);
|
||||
ResultGetters = std::move(RHS.ResultGetters);
|
||||
return *this;
|
||||
}
|
||||
AAManager &operator=(const AAManager &RHS) {
|
||||
FunctionResultGetters = RHS.FunctionResultGetters;
|
||||
ResultGetters = RHS.ResultGetters;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Register a specific AA result.
|
||||
template <typename AnalysisT> void registerFunctionAnalysis() {
|
||||
FunctionResultGetters.push_back(&getFunctionAAResultImpl<AnalysisT>);
|
||||
ResultGetters.push_back(&getFunctionAAResultImpl<AnalysisT>);
|
||||
}
|
||||
|
||||
/// Register a specific AA result.
|
||||
template <typename AnalysisT> void registerModuleAnalysis() {
|
||||
ResultGetters.push_back(&getModuleAAResultImpl<AnalysisT>);
|
||||
}
|
||||
|
||||
Result run(Function &F, AnalysisManager<Function> &AM) {
|
||||
Result R;
|
||||
for (auto &Getter : FunctionResultGetters)
|
||||
Result R(AM.getResult<TargetLibraryAnalysis>(F));
|
||||
for (auto &Getter : ResultGetters)
|
||||
(*Getter)(F, AM, R);
|
||||
return R;
|
||||
}
|
||||
|
||||
private:
|
||||
friend AnalysisInfoMixin<AAManager>;
|
||||
static char PassID;
|
||||
|
||||
SmallVector<void (*)(Function &F, AnalysisManager<Function> &AM,
|
||||
AAResults &AAResults),
|
||||
4> FunctionResultGetters;
|
||||
4> ResultGetters;
|
||||
|
||||
template <typename AnalysisT>
|
||||
static void getFunctionAAResultImpl(Function &F,
|
||||
@ -1030,6 +899,15 @@ private:
|
||||
AAResults &AAResults) {
|
||||
AAResults.addAAResult(AM.template getResult<AnalysisT>(F));
|
||||
}
|
||||
|
||||
template <typename AnalysisT>
|
||||
static void getModuleAAResultImpl(Function &F, AnalysisManager<Function> &AM,
|
||||
AAResults &AAResults) {
|
||||
auto &MAM =
|
||||
AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager();
|
||||
if (auto *R = MAM.template getCachedResult<AnalysisT>(*F.getParent()))
|
||||
AAResults.addAAResult(*R);
|
||||
}
|
||||
};
|
||||
|
||||
/// A wrapper pass to provide the legacy pass manager access to a suitably
|
||||
@ -1065,8 +943,16 @@ ImmutablePass *createExternalAAWrapperPass(
|
||||
/// A helper for the legacy pass manager to create a \c AAResults
|
||||
/// object populated to the best of our ability for a particular function when
|
||||
/// inside of a \c ModulePass or a \c CallGraphSCCPass.
|
||||
///
|
||||
/// If a \c ModulePass or a \c CallGraphSCCPass calls \p
|
||||
/// createLegacyPMAAResults, it also needs to call \p addUsedAAAnalyses in \p
|
||||
/// getAnalysisUsage.
|
||||
AAResults createLegacyPMAAResults(Pass &P, Function &F, BasicAAResult &BAR);
|
||||
|
||||
/// A helper for the legacy pass manager to populate \p AU to add uses to make
|
||||
/// sure the analyses required by \p createLegacyPMAAResults are available.
|
||||
void getAAResultsAnalysisUsage(AnalysisUsage &AU);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
70
contrib/llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h
Normal file
70
contrib/llvm/include/llvm/Analysis/AliasAnalysisEvaluator.h
Normal file
@ -0,0 +1,70 @@
|
||||
//===- AliasAnalysisEvaluator.h - Alias Analysis Accuracy Evaluator -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This file implements a simple N^2 alias analysis accuracy evaluator. The
|
||||
/// analysis result is a set of statistics of how many times the AA
|
||||
/// infrastructure provides each kind of alias result and mod/ref result when
|
||||
/// queried with all pairs of pointers in the function.
|
||||
///
|
||||
/// It can be used to evaluate a change in an alias analysis implementation,
|
||||
/// algorithm, or the AA pipeline infrastructure itself. It acts like a stable
|
||||
/// and easily tested consumer of all AA information exposed.
|
||||
///
|
||||
/// This is inspired and adapted from code by: Naveen Neelakantam, Francesco
|
||||
/// Spadini, and Wojciech Stryjewski.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_ALIASANALYSISEVALUATOR_H
|
||||
#define LLVM_ANALYSIS_ALIASANALYSISEVALUATOR_H
|
||||
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
class AAResults;
|
||||
|
||||
class AAEvaluator : public PassInfoMixin<AAEvaluator> {
|
||||
int64_t FunctionCount;
|
||||
int64_t NoAliasCount, MayAliasCount, PartialAliasCount, MustAliasCount;
|
||||
int64_t NoModRefCount, ModCount, RefCount, ModRefCount;
|
||||
|
||||
public:
|
||||
AAEvaluator()
|
||||
: FunctionCount(), NoAliasCount(), MayAliasCount(), PartialAliasCount(),
|
||||
MustAliasCount(), NoModRefCount(), ModCount(), RefCount(),
|
||||
ModRefCount() {}
|
||||
AAEvaluator(AAEvaluator &&Arg)
|
||||
: FunctionCount(Arg.FunctionCount), NoAliasCount(Arg.NoAliasCount),
|
||||
MayAliasCount(Arg.MayAliasCount),
|
||||
PartialAliasCount(Arg.PartialAliasCount),
|
||||
MustAliasCount(Arg.MustAliasCount), NoModRefCount(Arg.NoModRefCount),
|
||||
ModCount(Arg.ModCount), RefCount(Arg.RefCount),
|
||||
ModRefCount(Arg.ModRefCount) {
|
||||
Arg.FunctionCount = 0;
|
||||
}
|
||||
~AAEvaluator();
|
||||
|
||||
/// \brief Run the pass over the function.
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
|
||||
private:
|
||||
// Allow the legacy pass to run this using an internal API.
|
||||
friend class AAEvalLegacyPass;
|
||||
|
||||
void runInternal(Function &F, AAResults &AA);
|
||||
};
|
||||
|
||||
/// Create a wrapper of the above for the legacy pass manager.
|
||||
FunctionPass *createAAEvalPass();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -7,9 +7,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines two classes: AliasSetTracker and AliasSet. These interface
|
||||
// This file defines two classes: AliasSetTracker and AliasSet. These interfaces
|
||||
// are used to classify a collection of pointer references into a maximal number
|
||||
// of disjoint sets. Each AliasSet object constructed by the AliasSetTracker
|
||||
// of disjoint sets. Each AliasSet object constructed by the AliasSetTracker
|
||||
// object refers to memory disjoint from the other sets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -30,6 +30,7 @@ namespace llvm {
|
||||
class LoadInst;
|
||||
class StoreInst;
|
||||
class VAArgInst;
|
||||
class MemSetInst;
|
||||
class AliasSetTracker;
|
||||
class AliasSet;
|
||||
|
||||
@ -58,8 +59,12 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
return &NextInList;
|
||||
}
|
||||
|
||||
void updateSizeAndAAInfo(uint64_t NewSize, const AAMDNodes &NewAAInfo) {
|
||||
if (NewSize > Size) Size = NewSize;
|
||||
bool updateSizeAndAAInfo(uint64_t NewSize, const AAMDNodes &NewAAInfo) {
|
||||
bool SizeChanged = false;
|
||||
if (NewSize > Size) {
|
||||
Size = NewSize;
|
||||
SizeChanged = true;
|
||||
}
|
||||
|
||||
if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey())
|
||||
// We don't have a AAInfo yet. Set it to NewAAInfo.
|
||||
@ -67,12 +72,14 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
else if (AAInfo != NewAAInfo)
|
||||
// NewAAInfo conflicts with AAInfo.
|
||||
AAInfo = DenseMapInfo<AAMDNodes>::getTombstoneKey();
|
||||
|
||||
return SizeChanged;
|
||||
}
|
||||
|
||||
uint64_t getSize() const { return Size; }
|
||||
|
||||
/// getAAInfo - Return the AAInfo, or null if there is no
|
||||
/// information or conflicting information.
|
||||
/// Return the AAInfo, or null if there is no information or conflicting
|
||||
/// information.
|
||||
AAMDNodes getAAInfo() const {
|
||||
// If we have missing or conflicting AAInfo, return null.
|
||||
if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey() ||
|
||||
@ -111,11 +118,11 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
PointerRec *PtrList, **PtrListEnd; // Doubly linked list of nodes.
|
||||
AliasSet *Forward; // Forwarding pointer.
|
||||
|
||||
// All instructions without a specific address in this alias set.
|
||||
/// All instructions without a specific address in this alias set.
|
||||
std::vector<AssertingVH<Instruction> > UnknownInsts;
|
||||
|
||||
// RefCount - Number of nodes pointing to this AliasSet plus the number of
|
||||
// AliasSets forwarding to it.
|
||||
/// Number of nodes pointing to this AliasSet plus the number of AliasSets
|
||||
/// forwarding to it.
|
||||
unsigned RefCount : 28;
|
||||
|
||||
/// The kinds of access this alias set models.
|
||||
@ -143,8 +150,8 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
};
|
||||
unsigned Alias : 1;
|
||||
|
||||
// Volatile - True if this alias set contains volatile loads or stores.
|
||||
bool Volatile : 1;
|
||||
/// True if this alias set contains volatile loads or stores.
|
||||
unsigned Volatile : 1;
|
||||
|
||||
void addRef() { ++RefCount; }
|
||||
void dropRef(AliasSetTracker &AST) {
|
||||
@ -165,20 +172,18 @@ public:
|
||||
bool isMustAlias() const { return Alias == SetMustAlias; }
|
||||
bool isMayAlias() const { return Alias == SetMayAlias; }
|
||||
|
||||
// isVolatile - Return true if this alias set contains volatile loads or
|
||||
// stores.
|
||||
/// Return true if this alias set contains volatile loads or stores.
|
||||
bool isVolatile() const { return Volatile; }
|
||||
|
||||
/// isForwardingAliasSet - Return true if this alias set should be ignored as
|
||||
/// part of the AliasSetTracker object.
|
||||
/// Return true if this alias set should be ignored as part of the
|
||||
/// AliasSetTracker object.
|
||||
bool isForwardingAliasSet() const { return Forward; }
|
||||
|
||||
/// mergeSetIn - Merge the specified alias set into this alias set...
|
||||
///
|
||||
/// Merge the specified alias set into this alias set.
|
||||
void mergeSetIn(AliasSet &AS, AliasSetTracker &AST);
|
||||
|
||||
// Alias Set iteration - Allow access to all of the pointer which are part of
|
||||
// this alias set...
|
||||
// Alias Set iteration - Allow access to all of the pointers which are part of
|
||||
// this alias set.
|
||||
class iterator;
|
||||
iterator begin() const { return iterator(PtrList); }
|
||||
iterator end() const { return iterator(); }
|
||||
@ -236,9 +241,9 @@ private:
|
||||
return PtrList;
|
||||
}
|
||||
|
||||
/// getForwardedTarget - Return the real alias set this represents. If this
|
||||
/// has been merged with another set and is forwarding, return the ultimate
|
||||
/// destination set. This also implements the union-find collapsing as well.
|
||||
/// Return the real alias set this represents. If this has been merged with
|
||||
/// another set and is forwarding, return the ultimate destination set. This
|
||||
/// also implements the union-find collapsing as well.
|
||||
AliasSet *getForwardedTarget(AliasSetTracker &AST) {
|
||||
if (!Forward) return this;
|
||||
|
||||
@ -271,9 +276,8 @@ private:
|
||||
void setVolatile() { Volatile = true; }
|
||||
|
||||
public:
|
||||
/// aliasesPointer - Return true if the specified pointer "may" (or must)
|
||||
/// alias one of the members in the set.
|
||||
///
|
||||
/// Return true if the specified pointer "may" (or must) alias one of the
|
||||
/// members in the set.
|
||||
bool aliasesPointer(const Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo,
|
||||
AliasAnalysis &AA) const;
|
||||
bool aliasesUnknownInst(const Instruction *Inst, AliasAnalysis &AA) const;
|
||||
@ -285,8 +289,8 @@ inline raw_ostream& operator<<(raw_ostream &OS, const AliasSet &AS) {
|
||||
}
|
||||
|
||||
class AliasSetTracker {
|
||||
/// CallbackVH - A CallbackVH to arrange for AliasSetTracker to be
|
||||
/// notified whenever a Value is deleted.
|
||||
/// A CallbackVH to arrange for AliasSetTracker to be notified whenever a
|
||||
/// Value is deleted.
|
||||
class ASTCallbackVH final : public CallbackVH {
|
||||
AliasSetTracker *AST;
|
||||
void deleted() override;
|
||||
@ -296,8 +300,8 @@ class AliasSetTracker {
|
||||
ASTCallbackVH(Value *V, AliasSetTracker *AST = nullptr);
|
||||
ASTCallbackVH &operator=(Value *V);
|
||||
};
|
||||
/// ASTCallbackVHDenseMapInfo - Traits to tell DenseMap that tell us how to
|
||||
/// compare and hash the value handle.
|
||||
/// Traits to tell DenseMap that tell us how to compare and hash the value
|
||||
/// handle.
|
||||
struct ASTCallbackVHDenseMapInfo : public DenseMapInfo<Value *> {};
|
||||
|
||||
AliasAnalysis &AA;
|
||||
@ -311,15 +315,14 @@ class AliasSetTracker {
|
||||
PointerMapType PointerMap;
|
||||
|
||||
public:
|
||||
/// AliasSetTracker ctor - Create an empty collection of AliasSets, and use
|
||||
/// the specified alias analysis object to disambiguate load and store
|
||||
/// addresses.
|
||||
/// Create an empty collection of AliasSets, and use the specified alias
|
||||
/// analysis object to disambiguate load and store addresses.
|
||||
explicit AliasSetTracker(AliasAnalysis &aa) : AA(aa) {}
|
||||
~AliasSetTracker() { clear(); }
|
||||
|
||||
/// add methods - These methods are used to add different types of
|
||||
/// instructions to the alias sets. Adding a new instruction can result in
|
||||
/// one of three actions happening:
|
||||
/// These methods are used to add different types of instructions to the alias
|
||||
/// sets. Adding a new instruction can result in one of three actions
|
||||
/// happening:
|
||||
///
|
||||
/// 1. If the instruction doesn't alias any other sets, create a new set.
|
||||
/// 2. If the instruction aliases exactly one set, add it to the set
|
||||
@ -333,47 +336,46 @@ public:
|
||||
bool add(LoadInst *LI);
|
||||
bool add(StoreInst *SI);
|
||||
bool add(VAArgInst *VAAI);
|
||||
bool add(MemSetInst *MSI);
|
||||
bool add(Instruction *I); // Dispatch to one of the other add methods...
|
||||
void add(BasicBlock &BB); // Add all instructions in basic block
|
||||
void add(const AliasSetTracker &AST); // Add alias relations from another AST
|
||||
bool addUnknown(Instruction *I);
|
||||
|
||||
/// remove methods - These methods are used to remove all entries that might
|
||||
/// be aliased by the specified instruction. These methods return true if any
|
||||
/// alias sets were eliminated.
|
||||
// Remove a location
|
||||
/// These methods are used to remove all entries that might be aliased by the
|
||||
/// specified instruction. These methods return true if any alias sets were
|
||||
/// eliminated.
|
||||
bool remove(Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo);
|
||||
bool remove(LoadInst *LI);
|
||||
bool remove(StoreInst *SI);
|
||||
bool remove(VAArgInst *VAAI);
|
||||
bool remove(MemSetInst *MSI);
|
||||
bool remove(Instruction *I);
|
||||
void remove(AliasSet &AS);
|
||||
bool removeUnknown(Instruction *I);
|
||||
|
||||
void clear();
|
||||
|
||||
/// getAliasSets - Return the alias sets that are active.
|
||||
///
|
||||
/// Return the alias sets that are active.
|
||||
const ilist<AliasSet> &getAliasSets() const { return AliasSets; }
|
||||
|
||||
/// getAliasSetForPointer - Return the alias set that the specified pointer
|
||||
/// lives in. If the New argument is non-null, this method sets the value to
|
||||
/// true if a new alias set is created to contain the pointer (because the
|
||||
/// pointer didn't alias anything).
|
||||
/// Return the alias set that the specified pointer lives in. If the New
|
||||
/// argument is non-null, this method sets the value to true if a new alias
|
||||
/// set is created to contain the pointer (because the pointer didn't alias
|
||||
/// anything).
|
||||
AliasSet &getAliasSetForPointer(Value *P, uint64_t Size,
|
||||
const AAMDNodes &AAInfo,
|
||||
bool *New = nullptr);
|
||||
|
||||
/// getAliasSetForPointerIfExists - Return the alias set containing the
|
||||
/// location specified if one exists, otherwise return null.
|
||||
/// Return the alias set containing the location specified if one exists,
|
||||
/// otherwise return null.
|
||||
AliasSet *getAliasSetForPointerIfExists(const Value *P, uint64_t Size,
|
||||
const AAMDNodes &AAInfo) {
|
||||
return findAliasSetForPointer(P, Size, AAInfo);
|
||||
return mergeAliasSetsForPointer(P, Size, AAInfo);
|
||||
}
|
||||
|
||||
/// containsPointer - Return true if the specified location is represented by
|
||||
/// this alias set, false otherwise. This does not modify the AST object or
|
||||
/// alias sets.
|
||||
/// Return true if the specified location is represented by this alias set,
|
||||
/// false otherwise. This does not modify the AST object or alias sets.
|
||||
bool containsPointer(const Value *P, uint64_t Size,
|
||||
const AAMDNodes &AAInfo) const;
|
||||
|
||||
@ -381,23 +383,19 @@ public:
|
||||
/// members in any of the sets.
|
||||
bool containsUnknown(const Instruction *I) const;
|
||||
|
||||
/// getAliasAnalysis - Return the underlying alias analysis object used by
|
||||
/// this tracker.
|
||||
/// Return the underlying alias analysis object used by this tracker.
|
||||
AliasAnalysis &getAliasAnalysis() const { return AA; }
|
||||
|
||||
/// deleteValue method - This method is used to remove a pointer value from
|
||||
/// the AliasSetTracker entirely. It should be used when an instruction is
|
||||
/// deleted from the program to update the AST. If you don't use this, you
|
||||
/// would have dangling pointers to deleted instructions.
|
||||
///
|
||||
/// This method is used to remove a pointer value from the AliasSetTracker
|
||||
/// entirely. It should be used when an instruction is deleted from the
|
||||
/// program to update the AST. If you don't use this, you would have dangling
|
||||
/// pointers to deleted instructions.
|
||||
void deleteValue(Value *PtrVal);
|
||||
|
||||
/// copyValue - This method should be used whenever a preexisting value in the
|
||||
/// program is copied or cloned, introducing a new value. Note that it is ok
|
||||
/// for clients that use this method to introduce the same value multiple
|
||||
/// times: if the tracker already knows about a value, it will ignore the
|
||||
/// request.
|
||||
///
|
||||
/// This method should be used whenever a preexisting value in the program is
|
||||
/// copied or cloned, introducing a new value. Note that it is ok for clients
|
||||
/// that use this method to introduce the same value multiple times: if the
|
||||
/// tracker already knows about a value, it will ignore the request.
|
||||
void copyValue(Value *From, Value *To);
|
||||
|
||||
typedef ilist<AliasSet>::iterator iterator;
|
||||
@ -416,8 +414,8 @@ private:
|
||||
friend class AliasSet;
|
||||
void removeAliasSet(AliasSet *AS);
|
||||
|
||||
// getEntryFor - Just like operator[] on the map, except that it creates an
|
||||
// entry for the pointer if it doesn't already exist.
|
||||
/// Just like operator[] on the map, except that it creates an entry for the
|
||||
/// pointer if it doesn't already exist.
|
||||
AliasSet::PointerRec &getEntryFor(Value *V) {
|
||||
AliasSet::PointerRec *&Entry = PointerMap[ASTCallbackVH(V, this)];
|
||||
if (!Entry)
|
||||
@ -433,8 +431,8 @@ private:
|
||||
AS.Access |= E;
|
||||
return AS;
|
||||
}
|
||||
AliasSet *findAliasSetForPointer(const Value *Ptr, uint64_t Size,
|
||||
const AAMDNodes &AAInfo);
|
||||
AliasSet *mergeAliasSetsForPointer(const Value *Ptr, uint64_t Size,
|
||||
const AAMDNodes &AAInfo);
|
||||
|
||||
AliasSet *findAliasSetForUnknownInst(Instruction *Inst);
|
||||
};
|
||||
|
@ -22,16 +22,12 @@
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// FIXME: Replace this brittle forward declaration with the include of the new
|
||||
// PassManager.h when doing so doesn't break the PassManagerBuilder.
|
||||
template <typename IRUnitT> class AnalysisManager;
|
||||
class PreservedAnalyses;
|
||||
|
||||
/// \brief A cache of @llvm.assume calls within a function.
|
||||
///
|
||||
/// This cache provides fast lookup of assumptions within a function by caching
|
||||
@ -97,36 +93,31 @@ public:
|
||||
///
|
||||
/// This analysis is intended for use with the new pass manager and will vend
|
||||
/// assumption caches for a given function.
|
||||
class AssumptionAnalysis {
|
||||
class AssumptionAnalysis : public AnalysisInfoMixin<AssumptionAnalysis> {
|
||||
friend AnalysisInfoMixin<AssumptionAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef AssumptionCache Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Provide a name for the analysis for debugging and logging.
|
||||
static StringRef name() { return "AssumptionAnalysis"; }
|
||||
|
||||
AssumptionAnalysis() {}
|
||||
AssumptionAnalysis(const AssumptionAnalysis &Arg) {}
|
||||
AssumptionAnalysis(AssumptionAnalysis &&Arg) {}
|
||||
AssumptionAnalysis &operator=(const AssumptionAnalysis &RHS) { return *this; }
|
||||
AssumptionAnalysis &operator=(AssumptionAnalysis &&RHS) { return *this; }
|
||||
|
||||
AssumptionCache run(Function &F) { return AssumptionCache(F); }
|
||||
AssumptionCache run(Function &F, FunctionAnalysisManager &) {
|
||||
return AssumptionCache(F);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c AssumptionAnalysis results.
|
||||
class AssumptionPrinterPass {
|
||||
class AssumptionPrinterPass : public PassInfoMixin<AssumptionPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
static StringRef name() { return "AssumptionPrinterPass"; }
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief An immutable pass that tracks lazily created \c AssumptionCache
|
||||
|
@ -40,6 +40,7 @@ class BasicAAResult : public AAResultBase<BasicAAResult> {
|
||||
friend AAResultBase<BasicAAResult>;
|
||||
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo &TLI;
|
||||
AssumptionCache &AC;
|
||||
DominatorTree *DT;
|
||||
LoopInfo *LI;
|
||||
@ -48,13 +49,14 @@ public:
|
||||
BasicAAResult(const DataLayout &DL, const TargetLibraryInfo &TLI,
|
||||
AssumptionCache &AC, DominatorTree *DT = nullptr,
|
||||
LoopInfo *LI = nullptr)
|
||||
: AAResultBase(TLI), DL(DL), AC(AC), DT(DT), LI(LI) {}
|
||||
: AAResultBase(), DL(DL), TLI(TLI), AC(AC), DT(DT), LI(LI) {}
|
||||
|
||||
BasicAAResult(const BasicAAResult &Arg)
|
||||
: AAResultBase(Arg), DL(Arg.DL), AC(Arg.AC), DT(Arg.DT), LI(Arg.LI) {}
|
||||
BasicAAResult(BasicAAResult &&Arg)
|
||||
: AAResultBase(std::move(Arg)), DL(Arg.DL), AC(Arg.AC), DT(Arg.DT),
|
||||
: AAResultBase(Arg), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT),
|
||||
LI(Arg.LI) {}
|
||||
BasicAAResult(BasicAAResult &&Arg)
|
||||
: AAResultBase(std::move(Arg)), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC),
|
||||
DT(Arg.DT), LI(Arg.LI) {}
|
||||
|
||||
/// Handle invalidation events from the new pass manager.
|
||||
///
|
||||
@ -107,6 +109,20 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// Represents the internal structure of a GEP, decomposed into a base pointer,
|
||||
// constant offsets, and variable scaled indices.
|
||||
struct DecomposedGEP {
|
||||
// Base pointer of the GEP
|
||||
const Value *Base;
|
||||
// Total constant offset w.r.t the base from indexing into structs
|
||||
int64_t StructOffset;
|
||||
// Total constant offset w.r.t the base from indexing through
|
||||
// pointers/arrays/vectors
|
||||
int64_t OtherOffset;
|
||||
// Scaled variable (non-constant) indices.
|
||||
SmallVector<VariableGEPIndex, 4> VarIndices;
|
||||
};
|
||||
|
||||
/// Track alias queries to guard against recursion.
|
||||
typedef std::pair<MemoryLocation, MemoryLocation> LocPair;
|
||||
typedef SmallDenseMap<LocPair, AliasResult, 8> AliasCacheTy;
|
||||
@ -137,11 +153,13 @@ private:
|
||||
const DataLayout &DL, unsigned Depth, AssumptionCache *AC,
|
||||
DominatorTree *DT, bool &NSW, bool &NUW);
|
||||
|
||||
static const Value *
|
||||
DecomposeGEPExpression(const Value *V, int64_t &BaseOffs,
|
||||
SmallVectorImpl<VariableGEPIndex> &VarIndices,
|
||||
bool &MaxLookupReached, const DataLayout &DL,
|
||||
AssumptionCache *AC, DominatorTree *DT);
|
||||
static bool DecomposeGEPExpression(const Value *V, DecomposedGEP &Decomposed,
|
||||
const DataLayout &DL, AssumptionCache *AC, DominatorTree *DT);
|
||||
|
||||
static bool isGEPBaseAtNegativeOffset(const GEPOperator *GEPOp,
|
||||
const DecomposedGEP &DecompGEP, const DecomposedGEP &DecompObject,
|
||||
uint64_t ObjectAccessSize);
|
||||
|
||||
/// \brief A Heuristic for aliasGEP that searches for a constant offset
|
||||
/// between the variables.
|
||||
///
|
||||
@ -178,20 +196,14 @@ private:
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
class BasicAA {
|
||||
class BasicAA : public AnalysisInfoMixin<BasicAA> {
|
||||
friend AnalysisInfoMixin<BasicAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef BasicAAResult Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
BasicAAResult run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "BasicAliasAnalysis"; }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
BasicAAResult run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the BasicAAResult object.
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef LLVM_ANALYSIS_BLOCKFREQUENCYINFO_H
|
||||
#define LLVM_ANALYSIS_BLOCKFREQUENCYINFO_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/BlockFrequency.h"
|
||||
#include <climits>
|
||||
@ -30,12 +32,21 @@ class BlockFrequencyInfo {
|
||||
typedef BlockFrequencyInfoImpl<BasicBlock> ImplType;
|
||||
std::unique_ptr<ImplType> BFI;
|
||||
|
||||
void operator=(const BlockFrequencyInfo &) = delete;
|
||||
BlockFrequencyInfo(const BlockFrequencyInfo &) = delete;
|
||||
|
||||
public:
|
||||
BlockFrequencyInfo();
|
||||
BlockFrequencyInfo(const Function &F, const BranchProbabilityInfo &BPI,
|
||||
const LoopInfo &LI);
|
||||
BlockFrequencyInfo(BlockFrequencyInfo &&Arg);
|
||||
|
||||
BlockFrequencyInfo &operator=(BlockFrequencyInfo &&RHS);
|
||||
|
||||
~BlockFrequencyInfo();
|
||||
|
||||
const Function *getFunction() const;
|
||||
const BranchProbabilityInfo *getBPI() const;
|
||||
void view() const;
|
||||
|
||||
/// getblockFreq - Return block frequency. Return 0 if we don't have the
|
||||
@ -45,6 +56,11 @@ public:
|
||||
/// floating points.
|
||||
BlockFrequency getBlockFreq(const BasicBlock *BB) const;
|
||||
|
||||
/// \brief Returns the estimated profile count of \p BB.
|
||||
/// This computes the relative block frequency of \p BB and multiplies it by
|
||||
/// the enclosing function's count (if available) and returns the value.
|
||||
Optional<uint64_t> getBlockProfileCount(const BasicBlock *BB) const;
|
||||
|
||||
// Set the frequency of the given basic block.
|
||||
void setBlockFreq(const BasicBlock *BB, uint64_t Freq);
|
||||
|
||||
@ -65,6 +81,30 @@ public:
|
||||
void print(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
/// \brief Analysis pass which computes \c BlockFrequencyInfo.
|
||||
class BlockFrequencyAnalysis
|
||||
: public AnalysisInfoMixin<BlockFrequencyAnalysis> {
|
||||
friend AnalysisInfoMixin<BlockFrequencyAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
/// \brief Provide the result typedef for this analysis pass.
|
||||
typedef BlockFrequencyInfo Result;
|
||||
|
||||
/// \brief Run the analysis pass over a function and produce BFI.
|
||||
Result run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c BlockFrequencyInfo results.
|
||||
class BlockFrequencyPrinterPass
|
||||
: public PassInfoMixin<BlockFrequencyPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit BlockFrequencyPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Legacy analysis pass which computes \c BlockFrequencyInfo.
|
||||
class BlockFrequencyInfoWrapperPass : public FunctionPass {
|
||||
BlockFrequencyInfo BFI;
|
||||
|
@ -16,12 +16,16 @@
|
||||
#define LLVM_ANALYSIS_BLOCKFREQUENCYINFOIMPL_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/Support/BlockFrequency.h"
|
||||
#include "llvm/Support/BranchProbability.h"
|
||||
#include "llvm/Support/DOTGraphTraits.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/ScaledNumber.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <deque>
|
||||
@ -476,6 +480,8 @@ public:
|
||||
Scaled64 getFloatingBlockFreq(const BlockNode &Node) const;
|
||||
|
||||
BlockFrequency getBlockFreq(const BlockNode &Node) const;
|
||||
Optional<uint64_t> getBlockProfileCount(const Function &F,
|
||||
const BlockNode &Node) const;
|
||||
|
||||
void setBlockFreq(const BlockNode &Node, uint64_t Freq);
|
||||
|
||||
@ -915,11 +921,17 @@ public:
|
||||
BlockFrequency getBlockFreq(const BlockT *BB) const {
|
||||
return BlockFrequencyInfoImplBase::getBlockFreq(getNode(BB));
|
||||
}
|
||||
Optional<uint64_t> getBlockProfileCount(const Function &F,
|
||||
const BlockT *BB) const {
|
||||
return BlockFrequencyInfoImplBase::getBlockProfileCount(F, getNode(BB));
|
||||
}
|
||||
void setBlockFreq(const BlockT *BB, uint64_t Freq);
|
||||
Scaled64 getFloatingBlockFreq(const BlockT *BB) const {
|
||||
return BlockFrequencyInfoImplBase::getFloatingBlockFreq(getNode(BB));
|
||||
}
|
||||
|
||||
const BranchProbabilityInfoT &getBPI() const { return *BPI; }
|
||||
|
||||
/// \brief Print the frequencies for the current function.
|
||||
///
|
||||
/// Prints the frequencies for the blocks in the current function.
|
||||
@ -1173,12 +1185,10 @@ void BlockFrequencyInfoImpl<BT>::computeIrreducibleMass(
|
||||
updateLoopWithIrreducible(*OuterLoop);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A helper function that converts a branch probability into weight.
|
||||
inline uint32_t getWeightFromBranchProb(const BranchProbability Prob) {
|
||||
return Prob.getNumerator();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <class BT>
|
||||
bool
|
||||
@ -1224,6 +1234,115 @@ raw_ostream &BlockFrequencyInfoImpl<BT>::print(raw_ostream &OS) const {
|
||||
return OS;
|
||||
}
|
||||
|
||||
// Graph trait base class for block frequency information graph
|
||||
// viewer.
|
||||
|
||||
enum GVDAGType { GVDT_None, GVDT_Fraction, GVDT_Integer, GVDT_Count };
|
||||
|
||||
template <class BlockFrequencyInfoT, class BranchProbabilityInfoT>
|
||||
struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
|
||||
explicit BFIDOTGraphTraitsBase(bool isSimple = false)
|
||||
: DefaultDOTGraphTraits(isSimple) {}
|
||||
|
||||
typedef GraphTraits<BlockFrequencyInfoT *> GTraits;
|
||||
typedef typename GTraits::NodeType NodeType;
|
||||
typedef typename GTraits::ChildIteratorType EdgeIter;
|
||||
typedef typename GTraits::nodes_iterator NodeIter;
|
||||
|
||||
uint64_t MaxFrequency = 0;
|
||||
static std::string getGraphName(const BlockFrequencyInfoT *G) {
|
||||
return G->getFunction()->getName();
|
||||
}
|
||||
|
||||
std::string getNodeAttributes(const NodeType *Node,
|
||||
const BlockFrequencyInfoT *Graph,
|
||||
unsigned HotPercentThreshold = 0) {
|
||||
std::string Result;
|
||||
if (!HotPercentThreshold)
|
||||
return Result;
|
||||
|
||||
// Compute MaxFrequency on the fly:
|
||||
if (!MaxFrequency) {
|
||||
for (NodeIter I = GTraits::nodes_begin(Graph),
|
||||
E = GTraits::nodes_end(Graph);
|
||||
I != E; ++I) {
|
||||
NodeType &N = *I;
|
||||
MaxFrequency =
|
||||
std::max(MaxFrequency, Graph->getBlockFreq(&N).getFrequency());
|
||||
}
|
||||
}
|
||||
BlockFrequency Freq = Graph->getBlockFreq(Node);
|
||||
BlockFrequency HotFreq =
|
||||
(BlockFrequency(MaxFrequency) *
|
||||
BranchProbability::getBranchProbability(HotPercentThreshold, 100));
|
||||
|
||||
if (Freq < HotFreq)
|
||||
return Result;
|
||||
|
||||
raw_string_ostream OS(Result);
|
||||
OS << "color=\"red\"";
|
||||
OS.flush();
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string getNodeLabel(const NodeType *Node,
|
||||
const BlockFrequencyInfoT *Graph, GVDAGType GType) {
|
||||
std::string Result;
|
||||
raw_string_ostream OS(Result);
|
||||
|
||||
OS << Node->getName().str() << " : ";
|
||||
switch (GType) {
|
||||
case GVDT_Fraction:
|
||||
Graph->printBlockFreq(OS, Node);
|
||||
break;
|
||||
case GVDT_Integer:
|
||||
OS << Graph->getBlockFreq(Node).getFrequency();
|
||||
break;
|
||||
case GVDT_Count: {
|
||||
auto Count = Graph->getBlockProfileCount(Node);
|
||||
if (Count)
|
||||
OS << Count.getValue();
|
||||
else
|
||||
OS << "Unknown";
|
||||
break;
|
||||
}
|
||||
case GVDT_None:
|
||||
llvm_unreachable("If we are not supposed to render a graph we should "
|
||||
"never reach this point.");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string getEdgeAttributes(const NodeType *Node, EdgeIter EI,
|
||||
const BlockFrequencyInfoT *BFI,
|
||||
const BranchProbabilityInfoT *BPI,
|
||||
unsigned HotPercentThreshold = 0) {
|
||||
std::string Str;
|
||||
if (!BPI)
|
||||
return Str;
|
||||
|
||||
BranchProbability BP = BPI->getEdgeProbability(Node, EI);
|
||||
uint32_t N = BP.getNumerator();
|
||||
uint32_t D = BP.getDenominator();
|
||||
double Percent = 100.0 * N / D;
|
||||
raw_string_ostream OS(Str);
|
||||
OS << format("label=\"%.1f%%\"", Percent);
|
||||
|
||||
if (HotPercentThreshold) {
|
||||
BlockFrequency EFreq = BFI->getBlockFreq(Node) * BP;
|
||||
BlockFrequency HotFreq = BlockFrequency(MaxFrequency) *
|
||||
BranchProbability(HotPercentThreshold, 100);
|
||||
|
||||
if (EFreq >= HotFreq) {
|
||||
OS << ",color=\"red\"";
|
||||
}
|
||||
}
|
||||
|
||||
OS.flush();
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
@ -15,8 +15,11 @@
|
||||
#define LLVM_ANALYSIS_BRANCHPROBABILITYINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/BranchProbability.h"
|
||||
@ -40,7 +43,22 @@ class raw_ostream;
|
||||
class BranchProbabilityInfo {
|
||||
public:
|
||||
BranchProbabilityInfo() {}
|
||||
BranchProbabilityInfo(Function &F, const LoopInfo &LI) { calculate(F, LI); }
|
||||
BranchProbabilityInfo(const Function &F, const LoopInfo &LI) {
|
||||
calculate(F, LI);
|
||||
}
|
||||
|
||||
BranchProbabilityInfo(BranchProbabilityInfo &&Arg)
|
||||
: Probs(std::move(Arg.Probs)), LastF(Arg.LastF),
|
||||
PostDominatedByUnreachable(std::move(Arg.PostDominatedByUnreachable)),
|
||||
PostDominatedByColdCall(std::move(Arg.PostDominatedByColdCall)) {}
|
||||
|
||||
BranchProbabilityInfo &operator=(BranchProbabilityInfo &&RHS) {
|
||||
releaseMemory();
|
||||
Probs = std::move(RHS.Probs);
|
||||
PostDominatedByColdCall = std::move(RHS.PostDominatedByColdCall);
|
||||
PostDominatedByUnreachable = std::move(RHS.PostDominatedByUnreachable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void releaseMemory();
|
||||
|
||||
@ -74,7 +92,7 @@ public:
|
||||
///
|
||||
/// Given a basic block, look through its successors and if one exists for
|
||||
/// which \see isEdgeHot would return true, return that successor block.
|
||||
BasicBlock *getHotSucc(BasicBlock *BB) const;
|
||||
const BasicBlock *getHotSucc(const BasicBlock *BB) const;
|
||||
|
||||
/// \brief Print an edge's probability.
|
||||
///
|
||||
@ -98,9 +116,31 @@ public:
|
||||
return IsLikely ? LikelyProb : LikelyProb.getCompl();
|
||||
}
|
||||
|
||||
void calculate(Function &F, const LoopInfo& LI);
|
||||
void calculate(const Function &F, const LoopInfo &LI);
|
||||
|
||||
/// Forget analysis results for the given basic block.
|
||||
void eraseBlock(const BasicBlock *BB);
|
||||
|
||||
private:
|
||||
void operator=(const BranchProbabilityInfo &) = delete;
|
||||
BranchProbabilityInfo(const BranchProbabilityInfo &) = delete;
|
||||
|
||||
// We need to store CallbackVH's in order to correctly handle basic block
|
||||
// removal.
|
||||
class BasicBlockCallbackVH final : public CallbackVH {
|
||||
BranchProbabilityInfo *BPI;
|
||||
void deleted() override {
|
||||
assert(BPI != nullptr);
|
||||
BPI->eraseBlock(cast<BasicBlock>(getValPtr()));
|
||||
BPI->Handles.erase(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
BasicBlockCallbackVH(const Value *V, BranchProbabilityInfo *BPI=nullptr)
|
||||
: CallbackVH(const_cast<Value *>(V)), BPI(BPI) {}
|
||||
};
|
||||
DenseSet<BasicBlockCallbackVH, DenseMapInfo<Value*>> Handles;
|
||||
|
||||
// Since we allow duplicate edges from one basic block to another, we use
|
||||
// a pair (PredBlock and an index in the successors) to specify an edge.
|
||||
typedef std::pair<const BasicBlock *, unsigned> Edge;
|
||||
@ -116,22 +156,46 @@ private:
|
||||
DenseMap<Edge, BranchProbability> Probs;
|
||||
|
||||
/// \brief Track the last function we run over for printing.
|
||||
Function *LastF;
|
||||
const Function *LastF;
|
||||
|
||||
/// \brief Track the set of blocks directly succeeded by a returning block.
|
||||
SmallPtrSet<BasicBlock *, 16> PostDominatedByUnreachable;
|
||||
SmallPtrSet<const BasicBlock *, 16> PostDominatedByUnreachable;
|
||||
|
||||
/// \brief Track the set of blocks that always lead to a cold call.
|
||||
SmallPtrSet<BasicBlock *, 16> PostDominatedByColdCall;
|
||||
SmallPtrSet<const BasicBlock *, 16> PostDominatedByColdCall;
|
||||
|
||||
bool calcUnreachableHeuristics(BasicBlock *BB);
|
||||
bool calcMetadataWeights(BasicBlock *BB);
|
||||
bool calcColdCallHeuristics(BasicBlock *BB);
|
||||
bool calcPointerHeuristics(BasicBlock *BB);
|
||||
bool calcLoopBranchHeuristics(BasicBlock *BB, const LoopInfo &LI);
|
||||
bool calcZeroHeuristics(BasicBlock *BB);
|
||||
bool calcFloatingPointHeuristics(BasicBlock *BB);
|
||||
bool calcInvokeHeuristics(BasicBlock *BB);
|
||||
bool calcUnreachableHeuristics(const BasicBlock *BB);
|
||||
bool calcMetadataWeights(const BasicBlock *BB);
|
||||
bool calcColdCallHeuristics(const BasicBlock *BB);
|
||||
bool calcPointerHeuristics(const BasicBlock *BB);
|
||||
bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI);
|
||||
bool calcZeroHeuristics(const BasicBlock *BB);
|
||||
bool calcFloatingPointHeuristics(const BasicBlock *BB);
|
||||
bool calcInvokeHeuristics(const BasicBlock *BB);
|
||||
};
|
||||
|
||||
/// \brief Analysis pass which computes \c BranchProbabilityInfo.
|
||||
class BranchProbabilityAnalysis
|
||||
: public AnalysisInfoMixin<BranchProbabilityAnalysis> {
|
||||
friend AnalysisInfoMixin<BranchProbabilityAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
/// \brief Provide the result typedef for this analysis pass.
|
||||
typedef BranchProbabilityInfo Result;
|
||||
|
||||
/// \brief Run the analysis pass over a function and produce BPI.
|
||||
BranchProbabilityInfo run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c BranchProbabilityAnalysis results.
|
||||
class BranchProbabilityPrinterPass
|
||||
: public PassInfoMixin<BranchProbabilityPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit BranchProbabilityPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Legacy analysis pass which computes \c BranchProbabilityInfo.
|
||||
|
138
contrib/llvm/include/llvm/Analysis/CFLAndersAliasAnalysis.h
Normal file
138
contrib/llvm/include/llvm/Analysis/CFLAndersAliasAnalysis.h
Normal file
@ -0,0 +1,138 @@
|
||||
//=- CFLAndersAliasAnalysis.h - Unification-based Alias Analysis ---*- C++-*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This is the interface for LLVM's inclusion-based alias analysis
|
||||
/// implemented with CFL graph reachability.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H
|
||||
#define LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <forward_list>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class TargetLibraryInfo;
|
||||
|
||||
namespace cflaa {
|
||||
struct AliasSummary;
|
||||
}
|
||||
|
||||
class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
|
||||
friend AAResultBase<CFLAndersAAResult>;
|
||||
class FunctionInfo;
|
||||
|
||||
public:
|
||||
explicit CFLAndersAAResult(const TargetLibraryInfo &);
|
||||
CFLAndersAAResult(CFLAndersAAResult &&);
|
||||
~CFLAndersAAResult();
|
||||
|
||||
/// Handle invalidation events from the new pass manager.
|
||||
/// By definition, this result is stateless and so remains valid.
|
||||
bool invalidate(Function &, const PreservedAnalyses &) { return false; }
|
||||
/// Evict the given function from cache
|
||||
void evict(const Function &Fn);
|
||||
|
||||
/// \brief Get the alias summary for the given function
|
||||
/// Return nullptr if the summary is not found or not available
|
||||
const cflaa::AliasSummary *getAliasSummary(const Function &);
|
||||
|
||||
AliasResult query(const MemoryLocation &, const MemoryLocation &);
|
||||
AliasResult alias(const MemoryLocation &, const MemoryLocation &);
|
||||
|
||||
private:
|
||||
struct FunctionHandle final : public CallbackVH {
|
||||
FunctionHandle(Function *Fn, CFLAndersAAResult *Result)
|
||||
: CallbackVH(Fn), Result(Result) {
|
||||
assert(Fn != nullptr);
|
||||
assert(Result != nullptr);
|
||||
}
|
||||
|
||||
void deleted() override { removeSelfFromCache(); }
|
||||
void allUsesReplacedWith(Value *) override { removeSelfFromCache(); }
|
||||
|
||||
private:
|
||||
CFLAndersAAResult *Result;
|
||||
|
||||
void removeSelfFromCache() {
|
||||
assert(Result != nullptr);
|
||||
auto *Val = getValPtr();
|
||||
Result->evict(*cast<Function>(Val));
|
||||
setValPtr(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Ensures that the given function is available in the cache.
|
||||
/// Returns the appropriate entry from the cache.
|
||||
const Optional<FunctionInfo> &ensureCached(const Function &);
|
||||
|
||||
/// \brief Inserts the given Function into the cache.
|
||||
void scan(const Function &);
|
||||
|
||||
/// \brief Build summary for a given function
|
||||
FunctionInfo buildInfoFrom(const Function &);
|
||||
|
||||
const TargetLibraryInfo &TLI;
|
||||
|
||||
/// \brief Cached mapping of Functions to their StratifiedSets.
|
||||
/// If a function's sets are currently being built, it is marked
|
||||
/// in the cache as an Optional without a value. This way, if we
|
||||
/// have any kind of recursion, it is discernable from a function
|
||||
/// that simply has empty sets.
|
||||
DenseMap<const Function *, Optional<FunctionInfo>> Cache;
|
||||
|
||||
std::forward_list<FunctionHandle> Handles;
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
///
|
||||
/// FIXME: We really should refactor CFL to use the analysis more heavily, and
|
||||
/// in particular to leverage invalidation to trigger re-computation.
|
||||
class CFLAndersAA : public AnalysisInfoMixin<CFLAndersAA> {
|
||||
friend AnalysisInfoMixin<CFLAndersAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef CFLAndersAAResult Result;
|
||||
|
||||
CFLAndersAAResult run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the CFLAndersAAResult object.
|
||||
class CFLAndersAAWrapperPass : public ImmutablePass {
|
||||
std::unique_ptr<CFLAndersAAResult> Result;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
CFLAndersAAWrapperPass();
|
||||
|
||||
CFLAndersAAResult &getResult() { return *Result; }
|
||||
const CFLAndersAAResult &getResult() const { return *Result; }
|
||||
|
||||
void initializePass() override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createCFLAndersAAWrapperPass - This pass implements a set-based approach to
|
||||
// alias analysis.
|
||||
//
|
||||
ImmutablePass *createCFLAndersAAWrapperPass();
|
||||
}
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===- CFLAliasAnalysis.h - CFL-Based Alias Analysis Interface ---*- C++ -*-==//
|
||||
//=- CFLSteensAliasAnalysis.h - Unification-based Alias Analysis ---*- C++-*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,17 +7,18 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This is the interface for LLVM's primary stateless and local alias analysis.
|
||||
/// This is the interface for LLVM's unification-based alias analysis
|
||||
/// implemented with CFL graph reachability.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CFLALIASANALYSIS_H
|
||||
#define LLVM_ANALYSIS_CFLALIASANALYSIS_H
|
||||
#ifndef LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H
|
||||
#define LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
@ -26,14 +27,20 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CFLAAResult : public AAResultBase<CFLAAResult> {
|
||||
friend AAResultBase<CFLAAResult>;
|
||||
class TargetLibraryInfo;
|
||||
|
||||
struct FunctionInfo;
|
||||
namespace cflaa {
|
||||
struct AliasSummary;
|
||||
}
|
||||
|
||||
class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
|
||||
friend AAResultBase<CFLSteensAAResult>;
|
||||
class FunctionInfo;
|
||||
|
||||
public:
|
||||
explicit CFLAAResult(const TargetLibraryInfo &TLI);
|
||||
CFLAAResult(CFLAAResult &&Arg);
|
||||
explicit CFLSteensAAResult(const TargetLibraryInfo &);
|
||||
CFLSteensAAResult(CFLSteensAAResult &&Arg);
|
||||
~CFLSteensAAResult();
|
||||
|
||||
/// Handle invalidation events from the new pass manager.
|
||||
///
|
||||
@ -49,26 +56,23 @@ public:
|
||||
/// Returns the appropriate entry from the cache.
|
||||
const Optional<FunctionInfo> &ensureCached(Function *Fn);
|
||||
|
||||
/// \brief Get the alias summary for the given function
|
||||
/// Return nullptr if the summary is not found or not available
|
||||
const cflaa::AliasSummary *getAliasSummary(Function &Fn);
|
||||
|
||||
AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB);
|
||||
|
||||
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
|
||||
if (LocA.Ptr == LocB.Ptr) {
|
||||
if (LocA.Size == LocB.Size) {
|
||||
return MustAlias;
|
||||
} else {
|
||||
return PartialAlias;
|
||||
}
|
||||
}
|
||||
if (LocA.Ptr == LocB.Ptr)
|
||||
return LocA.Size == LocB.Size ? MustAlias : PartialAlias;
|
||||
|
||||
// Comparisons between global variables and other constants should be
|
||||
// handled by BasicAA.
|
||||
// TODO: ConstantExpr handling -- CFLAA may report NoAlias when comparing
|
||||
// a GlobalValue and ConstantExpr, but every query needs to have at least
|
||||
// one Value tied to a Function, and neither GlobalValues nor ConstantExprs
|
||||
// are.
|
||||
if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr)) {
|
||||
// CFLSteensAA may report NoAlias when comparing a GlobalValue and
|
||||
// ConstantExpr, but every query needs to have at least one Value tied to a
|
||||
// Function, and neither GlobalValues nor ConstantExprs are.
|
||||
if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr))
|
||||
return AAResultBase::alias(LocA, LocB);
|
||||
}
|
||||
|
||||
AliasResult QueryResult = query(LocA, LocB);
|
||||
if (QueryResult == MayAlias)
|
||||
@ -77,9 +81,19 @@ public:
|
||||
return QueryResult;
|
||||
}
|
||||
|
||||
/// Get the location associated with a pointer argument of a callsite.
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx);
|
||||
|
||||
/// Returns the behavior when calling the given call site.
|
||||
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
|
||||
/// Returns the behavior when calling the given function. For use when the
|
||||
/// call site is not known.
|
||||
FunctionModRefBehavior getModRefBehavior(const Function *F);
|
||||
|
||||
private:
|
||||
struct FunctionHandle final : public CallbackVH {
|
||||
FunctionHandle(Function *Fn, CFLAAResult *Result)
|
||||
FunctionHandle(Function *Fn, CFLSteensAAResult *Result)
|
||||
: CallbackVH(Fn), Result(Result) {
|
||||
assert(Fn != nullptr);
|
||||
assert(Result != nullptr);
|
||||
@ -89,7 +103,7 @@ private:
|
||||
void allUsesReplacedWith(Value *) override { removeSelfFromCache(); }
|
||||
|
||||
private:
|
||||
CFLAAResult *Result;
|
||||
CFLSteensAAResult *Result;
|
||||
|
||||
void removeSelfFromCache() {
|
||||
assert(Result != nullptr);
|
||||
@ -99,6 +113,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
const TargetLibraryInfo &TLI;
|
||||
|
||||
/// \brief Cached mapping of Functions to their StratifiedSets.
|
||||
/// If a function's sets are currently being built, it is marked
|
||||
/// in the cache as an Optional without a value. This way, if we
|
||||
@ -114,45 +130,38 @@ private:
|
||||
///
|
||||
/// FIXME: We really should refactor CFL to use the analysis more heavily, and
|
||||
/// in particular to leverage invalidation to trigger re-computation of sets.
|
||||
class CFLAA {
|
||||
public:
|
||||
typedef CFLAAResult Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
CFLAAResult run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "CFLAA"; }
|
||||
|
||||
private:
|
||||
class CFLSteensAA : public AnalysisInfoMixin<CFLSteensAA> {
|
||||
friend AnalysisInfoMixin<CFLSteensAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef CFLSteensAAResult Result;
|
||||
|
||||
CFLSteensAAResult run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the CFLAAResult object.
|
||||
class CFLAAWrapperPass : public ImmutablePass {
|
||||
std::unique_ptr<CFLAAResult> Result;
|
||||
/// Legacy wrapper pass to provide the CFLSteensAAResult object.
|
||||
class CFLSteensAAWrapperPass : public ImmutablePass {
|
||||
std::unique_ptr<CFLSteensAAResult> Result;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
CFLAAWrapperPass();
|
||||
CFLSteensAAWrapperPass();
|
||||
|
||||
CFLAAResult &getResult() { return *Result; }
|
||||
const CFLAAResult &getResult() const { return *Result; }
|
||||
CFLSteensAAResult &getResult() { return *Result; }
|
||||
const CFLSteensAAResult &getResult() const { return *Result; }
|
||||
|
||||
bool doInitialization(Module &M) override;
|
||||
bool doFinalization(Module &M) override;
|
||||
void initializePass() override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createCFLAAWrapperPass - This pass implements a set-based approach to
|
||||
// createCFLSteensAAWrapperPass - This pass implements a set-based approach to
|
||||
// alias analysis.
|
||||
//
|
||||
ImmutablePass *createCFLAAWrapperPass();
|
||||
ImmutablePass *createCFLSteensAAWrapperPass();
|
||||
}
|
||||
|
||||
#endif
|
@ -11,7 +11,7 @@
|
||||
/// 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
|
||||
/// traverse 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.
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern template class PassManager<LazyCallGraph::SCC>;
|
||||
/// \brief The CGSCC pass manager.
|
||||
///
|
||||
/// See the documentation for the PassManager template for details. It runs
|
||||
@ -33,6 +34,7 @@ namespace llvm {
|
||||
/// typedef serves as a convenient way to refer to this construct.
|
||||
typedef PassManager<LazyCallGraph::SCC> CGSCCPassManager;
|
||||
|
||||
extern template class AnalysisManager<LazyCallGraph::SCC>;
|
||||
/// \brief The CGSCC analysis manager.
|
||||
///
|
||||
/// See the documentation for the AnalysisManager template for detail
|
||||
@ -41,147 +43,16 @@ typedef PassManager<LazyCallGraph::SCC> CGSCCPassManager;
|
||||
/// pass manager infrastructure.
|
||||
typedef AnalysisManager<LazyCallGraph::SCC> CGSCCAnalysisManager;
|
||||
|
||||
/// \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();
|
||||
extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>;
|
||||
/// A proxy from a \c CGSCCAnalysisManager to a \c Module.
|
||||
typedef InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>
|
||||
CGSCCAnalysisManagerModuleProxy;
|
||||
|
||||
/// \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; }
|
||||
|
||||
static StringRef name() { return "CGSCCAnalysisManagerModuleProxy"; }
|
||||
|
||||
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; }
|
||||
|
||||
static StringRef name() { return "ModuleAnalysisManagerCGSCCProxy"; }
|
||||
|
||||
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;
|
||||
};
|
||||
extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
|
||||
LazyCallGraph::SCC>;
|
||||
/// A proxy from a \c ModuleAnalysisManager to an \c SCC.
|
||||
typedef OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC>
|
||||
ModuleAnalysisManagerCGSCCProxy;
|
||||
|
||||
/// \brief The core module pass which does a post-order walk of the SCCs and
|
||||
/// runs a CGSCC pass over each one.
|
||||
@ -192,21 +63,24 @@ private:
|
||||
/// \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 {
|
||||
template <typename CGSCCPassT>
|
||||
class ModuleToPostOrderCGSCCPassAdaptor
|
||||
: public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>> {
|
||||
public:
|
||||
explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass)
|
||||
: Pass(std::move(Pass)) {}
|
||||
explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false)
|
||||
: Pass(std::move(Pass)), DebugLogging(DebugLogging) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
ModuleToPostOrderCGSCCPassAdaptor(
|
||||
const ModuleToPostOrderCGSCCPassAdaptor &Arg)
|
||||
: Pass(Arg.Pass) {}
|
||||
: Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {}
|
||||
ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg)
|
||||
: Pass(std::move(Arg.Pass)) {}
|
||||
: Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {}
|
||||
friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS,
|
||||
ModuleToPostOrderCGSCCPassAdaptor &RHS) {
|
||||
using std::swap;
|
||||
swap(LHS.Pass, RHS.Pass);
|
||||
swap(LHS.DebugLogging, RHS.DebugLogging);
|
||||
}
|
||||
ModuleToPostOrderCGSCCPassAdaptor &
|
||||
operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) {
|
||||
@ -215,33 +89,36 @@ public:
|
||||
}
|
||||
|
||||
/// \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!");
|
||||
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
|
||||
// Setup the CGSCC analysis manager from its proxy.
|
||||
CGSCCAnalysisManager &CGAM =
|
||||
AM->getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager();
|
||||
AM.getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager();
|
||||
|
||||
// Get the call graph for this module.
|
||||
LazyCallGraph &CG = AM->getResult<LazyCallGraphAnalysis>(M);
|
||||
LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M);
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
for (LazyCallGraph::SCC &C : CG.postorder_sccs()) {
|
||||
PreservedAnalyses PassPA = Pass.run(C, &CGAM);
|
||||
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
|
||||
if (DebugLogging)
|
||||
dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n";
|
||||
|
||||
// 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. We
|
||||
// also update the preserved set of analyses to reflect that invalidated
|
||||
// analyses are now safe to preserve.
|
||||
// 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.
|
||||
PassPA = CGAM.invalidate(C, std::move(PassPA));
|
||||
for (LazyCallGraph::SCC &C : RC) {
|
||||
PreservedAnalyses PassPA = Pass.run(C, CGAM);
|
||||
|
||||
// Then intersect the preserved set so that invalidation of module
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
PA.intersect(std::move(PassPA));
|
||||
// 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. We
|
||||
// also update the preserved set of analyses to reflect that invalidated
|
||||
// analyses are now safe to preserve.
|
||||
// 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.
|
||||
PassPA = CGAM.invalidate(C, std::move(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
|
||||
@ -252,163 +129,29 @@ public:
|
||||
return PA;
|
||||
}
|
||||
|
||||
static StringRef name() { return "ModuleToPostOrderCGSCCPassAdaptor"; }
|
||||
|
||||
private:
|
||||
CGSCCPassT Pass;
|
||||
bool DebugLogging;
|
||||
};
|
||||
|
||||
/// \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 ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass));
|
||||
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) {
|
||||
return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass), DebugLogging);
|
||||
}
|
||||
|
||||
/// \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();
|
||||
extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
|
||||
LazyCallGraph::SCC>;
|
||||
/// A proxy from a \c FunctionAnalysisManager to an \c SCC.
|
||||
typedef InnerAnalysisManagerProxy<FunctionAnalysisManager, LazyCallGraph::SCC>
|
||||
FunctionAnalysisManagerCGSCCProxy;
|
||||
|
||||
/// \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; }
|
||||
|
||||
static StringRef name() { return "FunctionAnalysisManagerCGSCCProxy"; }
|
||||
|
||||
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 CGSCCAnalysisManagerFunctionProxy.
|
||||
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; }
|
||||
|
||||
static StringRef name() { return "CGSCCAnalysisManagerFunctionProxy"; }
|
||||
|
||||
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;
|
||||
};
|
||||
extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>;
|
||||
/// A proxy from a \c CGSCCAnalysisManager to a \c Function.
|
||||
typedef OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>
|
||||
CGSCCAnalysisManagerFunctionProxy;
|
||||
|
||||
/// \brief Adaptor that maps from a SCC to its functions.
|
||||
///
|
||||
@ -418,20 +161,23 @@ private:
|
||||
/// \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 {
|
||||
template <typename FunctionPassT>
|
||||
class CGSCCToFunctionPassAdaptor
|
||||
: public PassInfoMixin<CGSCCToFunctionPassAdaptor<FunctionPassT>> {
|
||||
public:
|
||||
explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass)
|
||||
: Pass(std::move(Pass)) {}
|
||||
explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false)
|
||||
: Pass(std::move(Pass)), DebugLogging(DebugLogging) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg)
|
||||
: Pass(Arg.Pass) {}
|
||||
: Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {}
|
||||
CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg)
|
||||
: Pass(std::move(Arg.Pass)) {}
|
||||
: Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {}
|
||||
friend void swap(CGSCCToFunctionPassAdaptor &LHS,
|
||||
CGSCCToFunctionPassAdaptor &RHS) {
|
||||
using std::swap;
|
||||
swap(LHS.Pass, RHS.Pass);
|
||||
swap(LHS.DebugLogging, RHS.DebugLogging);
|
||||
}
|
||||
CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) {
|
||||
swap(*this, RHS);
|
||||
@ -439,23 +185,24 @@ public:
|
||||
}
|
||||
|
||||
/// \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 run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
|
||||
// Setup the function analysis manager from its proxy.
|
||||
FunctionAnalysisManager &FAM =
|
||||
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
|
||||
|
||||
if (DebugLogging)
|
||||
dbgs() << "Running function passes across an SCC: " << C << "\n";
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
for (LazyCallGraph::Node *N : C) {
|
||||
PreservedAnalyses PassPA = Pass.run(N->getFunction(), FAM);
|
||||
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.
|
||||
// Also, update the preserved analyses to reflect that once invalidated
|
||||
// these can again be preserved.
|
||||
if (FAM)
|
||||
PassPA = FAM->invalidate(N->getFunction(), std::move(PassPA));
|
||||
PassPA = FAM.invalidate(N.getFunction(), std::move(PassPA));
|
||||
|
||||
// Then intersect the preserved set so that invalidation of module
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
@ -472,18 +219,18 @@ public:
|
||||
return PA;
|
||||
}
|
||||
|
||||
static StringRef name() { return "CGSCCToFunctionPassAdaptor"; }
|
||||
|
||||
private:
|
||||
FunctionPassT Pass;
|
||||
bool DebugLogging;
|
||||
};
|
||||
|
||||
/// \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 CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
|
||||
createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) {
|
||||
return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass),
|
||||
DebugLogging);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <map>
|
||||
@ -294,20 +295,27 @@ private:
|
||||
/// 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 {
|
||||
class CallGraphAnalysis : public AnalysisInfoMixin<CallGraphAnalysis> {
|
||||
friend AnalysisInfoMixin<CallGraphAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
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); }
|
||||
CallGraph run(Module &M, ModuleAnalysisManager &) { return CallGraph(M); }
|
||||
};
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
/// \brief Printer pass for the \c CallGraphAnalysis results.
|
||||
class CallGraphPrinterPass : public PassInfoMixin<CallGraphPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit CallGraphPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM);
|
||||
};
|
||||
|
||||
/// \brief The \c ModulePass which wraps up a \c CallGraph and the logic to
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/PassSupport.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -77,15 +78,21 @@ public:
|
||||
/// the call graph. If the derived class implements this method, it should
|
||||
/// always explicitly call the implementation here.
|
||||
void getAnalysisUsage(AnalysisUsage &Info) const override;
|
||||
|
||||
protected:
|
||||
/// Optional passes call this function to check whether the pass should be
|
||||
/// skipped. This is the case when optimization bisect is over the limit.
|
||||
bool skipSCC(CallGraphSCC &SCC) const;
|
||||
};
|
||||
|
||||
/// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
|
||||
class CallGraphSCC {
|
||||
const CallGraph &CG; // The call graph for this SCC.
|
||||
void *Context; // The CGPassManager object that is vending this.
|
||||
std::vector<CallGraphNode*> Nodes;
|
||||
|
||||
public:
|
||||
CallGraphSCC(void *context) : Context(context) {}
|
||||
CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {}
|
||||
|
||||
void initialize(CallGraphNode *const *I, CallGraphNode *const *E) {
|
||||
Nodes.assign(I, E);
|
||||
@ -101,6 +108,25 @@ public:
|
||||
typedef std::vector<CallGraphNode *>::const_iterator iterator;
|
||||
iterator begin() const { return Nodes.begin(); }
|
||||
iterator end() const { return Nodes.end(); }
|
||||
|
||||
const CallGraph &getCallGraph() { return CG; }
|
||||
};
|
||||
|
||||
void initializeDummyCGSCCPassPass(PassRegistry &);
|
||||
|
||||
/// This pass is required by interprocedural register allocation. It forces
|
||||
/// codegen to follow bottom up order on call graph.
|
||||
class DummyCGSCCPass : public CallGraphSCCPass {
|
||||
public:
|
||||
static char ID;
|
||||
DummyCGSCCPass() : CallGraphSCCPass(ID) {
|
||||
PassRegistry &Registry = *PassRegistry::getPassRegistry();
|
||||
initializeDummyCGSCCPassPass(Registry);
|
||||
};
|
||||
bool runOnSCC(CallGraphSCC &SCC) override { return false; }
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -17,10 +17,10 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ModulePass;
|
||||
class ModulePass;
|
||||
|
||||
ModulePass *createCallGraphViewerPass();
|
||||
ModulePass *createCallGraphPrinterPass();
|
||||
ModulePass *createCallGraphViewerPass();
|
||||
ModulePass *createCallGraphDOTPrinterPass();
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -42,50 +42,48 @@ bool callIsSmall(ImmutableCallSite CS);
|
||||
struct CodeMetrics {
|
||||
/// \brief True if this function contains a call to setjmp or other functions
|
||||
/// with attribute "returns twice" without having the attribute itself.
|
||||
bool exposesReturnsTwice;
|
||||
bool exposesReturnsTwice = false;
|
||||
|
||||
/// \brief True if this function calls itself.
|
||||
bool isRecursive;
|
||||
bool isRecursive = false;
|
||||
|
||||
/// \brief True if this function cannot be duplicated.
|
||||
///
|
||||
/// True if this function contains one or more indirect branches, or it contains
|
||||
/// one or more 'noduplicate' instructions.
|
||||
bool notDuplicatable;
|
||||
bool notDuplicatable = false;
|
||||
|
||||
/// \brief True if this function contains a call to a convergent function.
|
||||
bool convergent = false;
|
||||
|
||||
/// \brief True if this function calls alloca (in the C sense).
|
||||
bool usesDynamicAlloca;
|
||||
bool usesDynamicAlloca = false;
|
||||
|
||||
/// \brief Number of instructions in the analyzed blocks.
|
||||
unsigned NumInsts;
|
||||
unsigned NumInsts = false;
|
||||
|
||||
/// \brief Number of analyzed blocks.
|
||||
unsigned NumBlocks;
|
||||
unsigned NumBlocks = false;
|
||||
|
||||
/// \brief Keeps track of basic block code size estimates.
|
||||
DenseMap<const BasicBlock *, unsigned> NumBBInsts;
|
||||
|
||||
/// \brief Keep track of the number of calls to 'big' functions.
|
||||
unsigned NumCalls;
|
||||
unsigned NumCalls = false;
|
||||
|
||||
/// \brief The number of calls to internal functions with a single caller.
|
||||
///
|
||||
/// These are likely targets for future inlining, likely exposed by
|
||||
/// interleaved devirtualization.
|
||||
unsigned NumInlineCandidates;
|
||||
unsigned NumInlineCandidates = 0;
|
||||
|
||||
/// \brief How many instructions produce vector values.
|
||||
///
|
||||
/// The inliner is more aggressive with inlining vector kernels.
|
||||
unsigned NumVectorInsts;
|
||||
unsigned NumVectorInsts = 0;
|
||||
|
||||
/// \brief How many 'ret' instructions the blocks contain.
|
||||
unsigned NumRets;
|
||||
|
||||
CodeMetrics()
|
||||
: exposesReturnsTwice(false), isRecursive(false), notDuplicatable(false),
|
||||
usesDynamicAlloca(false), NumInsts(0), NumBlocks(0), NumCalls(0),
|
||||
NumInlineCandidates(0), NumVectorInsts(0), NumRets(0) {}
|
||||
unsigned NumRets = 0;
|
||||
|
||||
/// \brief Add information about a block to the current state.
|
||||
void analyzeBasicBlock(const BasicBlock *BB, const TargetTransformInfo &TTI,
|
||||
|
@ -21,30 +21,36 @@
|
||||
#define LLVM_ANALYSIS_CONSTANTFOLDING_H
|
||||
|
||||
namespace llvm {
|
||||
class Constant;
|
||||
class ConstantExpr;
|
||||
class Instruction;
|
||||
class DataLayout;
|
||||
class TargetLibraryInfo;
|
||||
class Function;
|
||||
class Type;
|
||||
template<typename T>
|
||||
class ArrayRef;
|
||||
class APInt;
|
||||
template <typename T> class ArrayRef;
|
||||
class Constant;
|
||||
class ConstantExpr;
|
||||
class DataLayout;
|
||||
class Function;
|
||||
class GlobalValue;
|
||||
class Instruction;
|
||||
class TargetLibraryInfo;
|
||||
class Type;
|
||||
|
||||
/// If this constant is a constant offset from a global, return the global and
|
||||
/// the constant. Because of constantexprs, this function is recursive.
|
||||
bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset,
|
||||
const DataLayout &DL);
|
||||
|
||||
/// ConstantFoldInstruction - Try to constant fold the specified instruction.
|
||||
/// If successful, the constant result is returned, if not, null is returned.
|
||||
/// Note that this fails if not all of the operands are constant. Otherwise,
|
||||
/// this function can only fail when attempting to fold instructions like loads
|
||||
/// and stores, which have no constant expression form.
|
||||
Constant *ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
Constant *ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldConstantExpression - Attempt to fold the constant expression
|
||||
/// using the specified DataLayout. If successful, the constant result is
|
||||
/// result is returned, if not, null is returned.
|
||||
Constant *
|
||||
ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
Constant *
|
||||
ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
|
||||
/// specified operands. If successful, the constant result is returned, if not,
|
||||
@ -52,19 +58,42 @@ namespace llvm {
|
||||
/// fold instructions like loads and stores, which have no constant expression
|
||||
/// form.
|
||||
///
|
||||
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
|
||||
ArrayRef<Constant *> Ops,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
Constant *ConstantFoldInstOperands(Instruction *I, ArrayRef<Constant *> Ops,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
|
||||
/// specified operands. If successful, the constant result is returned, if not,
|
||||
/// null is returned. Note that this function can fail when attempting to
|
||||
/// fold instructions like loads and stores, which have no constant expression
|
||||
/// form.
|
||||
///
|
||||
/// This function doesn't work for compares (use ConstantFoldCompareInstOperands
|
||||
/// for this) and GEPs.
|
||||
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
|
||||
ArrayRef<Constant *> Ops,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
|
||||
/// instruction (icmp/fcmp) with the specified operands. If it fails, it
|
||||
/// returns a constant expression of the specified operands.
|
||||
///
|
||||
Constant *
|
||||
ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS,
|
||||
Constant *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
Constant *
|
||||
ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS,
|
||||
Constant *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// \brief Attempt to constant fold a binary operation with the specified
|
||||
/// operands. If it fails, it returns a constant expression of the specified
|
||||
/// operands.
|
||||
Constant *ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
|
||||
Constant *RHS, const DataLayout &DL);
|
||||
|
||||
/// \brief Attempt to constant fold a cast with the specified operand. If it
|
||||
/// fails, it returns a constant expression of the specified operand.
|
||||
Constant *ConstantFoldCastOperand(unsigned Opcode, Constant *C, Type *DestTy,
|
||||
const DataLayout &DL);
|
||||
|
||||
/// ConstantFoldInsertValueInstruction - Attempt to constant fold an insertvalue
|
||||
/// instruction with the specified operands and indices. The constant result is
|
||||
@ -86,7 +115,7 @@ Constant *ConstantFoldExtractElementInstruction(Constant *Val, Constant *Idx);
|
||||
/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would
|
||||
/// produce if it is constant and determinable. If this is not determinable,
|
||||
/// return null.
|
||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout &DL);
|
||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty, const DataLayout &DL);
|
||||
|
||||
/// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a
|
||||
/// getelementptr constantexpr, return the constant value being addressed by the
|
||||
@ -98,7 +127,7 @@ Constant *ConstantFoldLoadThroughGEPConstantExpr(Constant *C, ConstantExpr *CE);
|
||||
/// return the constant value being addressed by a virtual load, or null if
|
||||
/// something is funny and we can't decide.
|
||||
Constant *ConstantFoldLoadThroughGEPIndices(Constant *C,
|
||||
ArrayRef<Constant*> Indices);
|
||||
ArrayRef<Constant *> Indices);
|
||||
|
||||
/// canConstantFoldCallTo - Return true if its even possible to fold a call to
|
||||
/// the specified function.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -35,40 +36,81 @@ class Instruction;
|
||||
class DominatorTree;
|
||||
class AssumptionCache;
|
||||
|
||||
struct DemandedBits : public FunctionPass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
DemandedBits();
|
||||
class DemandedBits {
|
||||
public:
|
||||
DemandedBits(Function &F, AssumptionCache &AC, DominatorTree &DT) :
|
||||
F(F), AC(AC), DT(DT), Analyzed(false) {}
|
||||
|
||||
bool runOnFunction(Function& F) override;
|
||||
void getAnalysisUsage(AnalysisUsage& AU) const override;
|
||||
void print(raw_ostream &OS, const Module *M) const override;
|
||||
|
||||
/// Return the bits demanded from instruction I.
|
||||
APInt getDemandedBits(Instruction *I);
|
||||
|
||||
/// Return true if, during analysis, I could not be reached.
|
||||
bool isInstructionDead(Instruction *I);
|
||||
|
||||
void print(raw_ostream &OS);
|
||||
|
||||
private:
|
||||
Function &F;
|
||||
AssumptionCache &AC;
|
||||
DominatorTree &DT;
|
||||
|
||||
void performAnalysis();
|
||||
void determineLiveOperandBits(const Instruction *UserI,
|
||||
const Instruction *I, unsigned OperandNo,
|
||||
const APInt &AOut, APInt &AB,
|
||||
APInt &KnownZero, APInt &KnownOne,
|
||||
APInt &KnownZero2, APInt &KnownOne2);
|
||||
const Instruction *I, unsigned OperandNo,
|
||||
const APInt &AOut, APInt &AB,
|
||||
APInt &KnownZero, APInt &KnownOne,
|
||||
APInt &KnownZero2, APInt &KnownOne2);
|
||||
|
||||
AssumptionCache *AC;
|
||||
DominatorTree *DT;
|
||||
Function *F;
|
||||
bool Analyzed;
|
||||
|
||||
// The set of visited instructions (non-integer-typed only).
|
||||
SmallPtrSet<Instruction*, 128> Visited;
|
||||
SmallPtrSet<Instruction*, 32> Visited;
|
||||
DenseMap<Instruction *, APInt> AliveBits;
|
||||
};
|
||||
|
||||
class DemandedBitsWrapperPass : public FunctionPass {
|
||||
private:
|
||||
mutable Optional<DemandedBits> DB;
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
DemandedBitsWrapperPass();
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// Clean up memory in between runs
|
||||
void releaseMemory() override;
|
||||
|
||||
DemandedBits &getDemandedBits() { return *DB; }
|
||||
|
||||
void print(raw_ostream &OS, const Module *M) const override;
|
||||
};
|
||||
|
||||
/// An analysis that produces \c DemandedBits for a function.
|
||||
class DemandedBitsAnalysis : public AnalysisInfoMixin<DemandedBitsAnalysis> {
|
||||
friend AnalysisInfoMixin<DemandedBitsAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
/// \brief Provide the result typedef for this analysis pass.
|
||||
typedef DemandedBits Result;
|
||||
|
||||
/// \brief Run the analysis pass over a function and produce demanded bits
|
||||
/// information.
|
||||
DemandedBits run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for DemandedBits
|
||||
class DemandedBitsPrinterPass : public PassInfoMixin<DemandedBitsPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit DemandedBitsPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Create a demanded bits analysis pass.
|
||||
FunctionPass *createDemandedBitsPass();
|
||||
FunctionPass *createDemandedBitsWrapperPass();
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -41,12 +41,12 @@
|
||||
#define LLVM_ANALYSIS_DEPENDENCEANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/SmallBitVector.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> class ArrayRef;
|
||||
class Loop;
|
||||
class LoopInfo;
|
||||
class ScalarEvolution;
|
||||
@ -206,7 +206,7 @@ namespace llvm {
|
||||
private:
|
||||
Instruction *Src, *Dst;
|
||||
const Dependence *NextPredecessor, *NextSuccessor;
|
||||
friend class DependenceAnalysis;
|
||||
friend class DependenceInfo;
|
||||
};
|
||||
|
||||
/// FullDependence - This class represents a dependence between two memory
|
||||
@ -274,16 +274,17 @@ namespace llvm {
|
||||
bool LoopIndependent;
|
||||
bool Consistent; // Init to true, then refine.
|
||||
std::unique_ptr<DVEntry[]> DV;
|
||||
friend class DependenceAnalysis;
|
||||
friend class DependenceInfo;
|
||||
};
|
||||
|
||||
/// DependenceAnalysis - This class is the main dependence-analysis driver.
|
||||
/// DependenceInfo - This class is the main dependence-analysis driver.
|
||||
///
|
||||
class DependenceAnalysis : public FunctionPass {
|
||||
void operator=(const DependenceAnalysis &) = delete;
|
||||
DependenceAnalysis(const DependenceAnalysis &) = delete;
|
||||
|
||||
class DependenceInfo {
|
||||
public:
|
||||
DependenceInfo(Function *F, AliasAnalysis *AA, ScalarEvolution *SE,
|
||||
LoopInfo *LI)
|
||||
: AA(AA), SE(SE), LI(LI), F(F) {}
|
||||
|
||||
/// depends - Tests for a dependence between the Src and Dst instructions.
|
||||
/// Returns NULL if no dependence; otherwise, returns a Dependence (or a
|
||||
/// FullDependence) with as much information as can be gleaned.
|
||||
@ -336,6 +337,8 @@ namespace llvm {
|
||||
/// both loops.
|
||||
const SCEV *getSplitIteration(const Dependence &Dep, unsigned Level);
|
||||
|
||||
Function *getFunction() const { return F; }
|
||||
|
||||
private:
|
||||
AliasAnalysis *AA;
|
||||
ScalarEvolution *SE;
|
||||
@ -919,22 +922,41 @@ namespace llvm {
|
||||
|
||||
bool tryDelinearize(Instruction *Src, Instruction *Dst,
|
||||
SmallVectorImpl<Subscript> &Pair);
|
||||
}; // class DependenceInfo
|
||||
|
||||
/// \brief AnalysisPass to compute dependence information in a function
|
||||
class DependenceAnalysis : public AnalysisInfoMixin<DependenceAnalysis> {
|
||||
public:
|
||||
typedef DependenceInfo Result;
|
||||
Result run(Function &F, FunctionAnalysisManager &FAM);
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
friend struct AnalysisInfoMixin<DependenceAnalysis>;
|
||||
}; // class DependenceAnalysis
|
||||
|
||||
/// \brief Legacy pass manager pass to access dependence information
|
||||
class DependenceAnalysisWrapperPass : public FunctionPass {
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
DependenceAnalysis() : FunctionPass(ID) {
|
||||
initializeDependenceAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
DependenceAnalysisWrapperPass() : FunctionPass(ID) {
|
||||
initializeDependenceAnalysisWrapperPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
void releaseMemory() override;
|
||||
void getAnalysisUsage(AnalysisUsage &) const override;
|
||||
void print(raw_ostream &, const Module * = nullptr) const override;
|
||||
}; // class DependenceAnalysis
|
||||
DependenceInfo &getDI() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<DependenceInfo> info;
|
||||
}; // class DependenceAnalysisWrapperPass
|
||||
|
||||
/// createDependenceAnalysisPass - This creates an instance of the
|
||||
/// DependenceAnalysis pass.
|
||||
FunctionPass *createDependenceAnalysisPass();
|
||||
/// DependenceAnalysis wrapper pass.
|
||||
FunctionPass *createDependenceAnalysisWrapperPass();
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define LLVM_ANALYSIS_DOMINANCEFRONTIER_H
|
||||
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
@ -133,63 +134,24 @@ public:
|
||||
const DomSetType &calculate(const DomTreeT &DT, const DomTreeNodeT *Node);
|
||||
};
|
||||
|
||||
class DominanceFrontier : public FunctionPass {
|
||||
ForwardDominanceFrontierBase<BasicBlock> Base;
|
||||
|
||||
class DominanceFrontier : public ForwardDominanceFrontierBase<BasicBlock> {
|
||||
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;
|
||||
};
|
||||
|
||||
class DominanceFrontierWrapperPass : public FunctionPass {
|
||||
DominanceFrontier DF;
|
||||
public:
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
|
||||
DominanceFrontier();
|
||||
DominanceFrontierWrapperPass();
|
||||
|
||||
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);
|
||||
}
|
||||
DominanceFrontier &getDominanceFrontier() { return DF; }
|
||||
const DominanceFrontier &getDominanceFrontier() const { return DF; }
|
||||
|
||||
void releaseMemory() override;
|
||||
|
||||
@ -205,6 +167,30 @@ public:
|
||||
extern template class DominanceFrontierBase<BasicBlock>;
|
||||
extern template class ForwardDominanceFrontierBase<BasicBlock>;
|
||||
|
||||
/// \brief Analysis pass which computes a \c DominanceFrontier.
|
||||
class DominanceFrontierAnalysis
|
||||
: public AnalysisInfoMixin<DominanceFrontierAnalysis> {
|
||||
friend AnalysisInfoMixin<DominanceFrontierAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
/// \brief Provide the result typedef for this analysis pass.
|
||||
typedef DominanceFrontier Result;
|
||||
|
||||
/// \brief Run the analysis pass over a function and produce a dominator tree.
|
||||
DominanceFrontier run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c DominanceFrontier.
|
||||
class DominanceFrontierPrinterPass
|
||||
: public PassInfoMixin<DominanceFrontierPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit DominanceFrontierPrinterPass(raw_ostream &OS);
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -23,12 +23,15 @@ enum class EHPersonality {
|
||||
Unknown,
|
||||
GNU_Ada,
|
||||
GNU_C,
|
||||
GNU_C_SjLj,
|
||||
GNU_CXX,
|
||||
GNU_CXX_SjLj,
|
||||
GNU_ObjC,
|
||||
MSVC_X86SEH,
|
||||
MSVC_Win64SEH,
|
||||
MSVC_CXX,
|
||||
CoreCLR
|
||||
CoreCLR,
|
||||
Rust
|
||||
};
|
||||
|
||||
/// \brief See if the given exception handling personality function is one
|
||||
|
@ -35,6 +35,7 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> {
|
||||
class FunctionInfo;
|
||||
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo &TLI;
|
||||
|
||||
/// The globals that do not have their addresses taken.
|
||||
SmallPtrSet<const GlobalValue *, 8> NonAddressTakenGlobals;
|
||||
@ -76,6 +77,7 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> {
|
||||
|
||||
public:
|
||||
GlobalsAAResult(GlobalsAAResult &&Arg);
|
||||
~GlobalsAAResult();
|
||||
|
||||
static GlobalsAAResult analyzeModule(Module &M, const TargetLibraryInfo &TLI,
|
||||
CallGraph &CG);
|
||||
@ -116,20 +118,14 @@ private:
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
class GlobalsAA {
|
||||
class GlobalsAA : public AnalysisInfoMixin<GlobalsAA> {
|
||||
friend AnalysisInfoMixin<GlobalsAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef GlobalsAAResult Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
GlobalsAAResult run(Module &M, AnalysisManager<Module> *AM);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "GlobalsAA"; }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
GlobalsAAResult run(Module &M, AnalysisManager<Module> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the GlobalsAAResult object.
|
||||
|
@ -117,7 +117,7 @@ private:
|
||||
mutable ilist_node<IVStrideUse> Sentinel;
|
||||
};
|
||||
|
||||
class IVUsers : public LoopPass {
|
||||
class IVUsers {
|
||||
friend class IVStrideUse;
|
||||
Loop *L;
|
||||
AssumptionCache *AC;
|
||||
@ -133,15 +133,9 @@ class IVUsers : public LoopPass {
|
||||
// Ephemeral values used by @llvm.assume in this function.
|
||||
SmallPtrSet<const Value *, 32> EphValues;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnLoop(Loop *L, LPPassManager &LPM) override;
|
||||
|
||||
void releaseMemory() override;
|
||||
|
||||
public:
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
IVUsers();
|
||||
IVUsers(Loop *L, AssumptionCache *AC, LoopInfo *LI, DominatorTree *DT,
|
||||
ScalarEvolution *SE);
|
||||
|
||||
Loop *getLoop() const { return L; }
|
||||
|
||||
@ -173,16 +167,58 @@ public:
|
||||
return Processed.count(Inst);
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override;
|
||||
void releaseMemory();
|
||||
|
||||
void print(raw_ostream &OS, const Module * = nullptr) const;
|
||||
|
||||
/// dump - This method is used for debugging.
|
||||
void dump() const;
|
||||
|
||||
protected:
|
||||
bool AddUsersImpl(Instruction *I, SmallPtrSetImpl<Loop*> &SimpleLoopNests);
|
||||
};
|
||||
|
||||
Pass *createIVUsersPass();
|
||||
|
||||
class IVUsersWrapperPass : public LoopPass {
|
||||
std::unique_ptr<IVUsers> IU;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
IVUsersWrapperPass();
|
||||
|
||||
IVUsers &getIU() { return *IU; }
|
||||
const IVUsers &getIU() const { return *IU; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnLoop(Loop *L, LPPassManager &LPM) override;
|
||||
|
||||
void releaseMemory() override;
|
||||
|
||||
void print(raw_ostream &OS, const Module * = nullptr) const override;
|
||||
};
|
||||
|
||||
/// Analysis pass that exposes the \c IVUsers for a loop.
|
||||
class IVUsersAnalysis : public AnalysisInfoMixin<IVUsersAnalysis> {
|
||||
friend AnalysisInfoMixin<IVUsersAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef IVUsers Result;
|
||||
|
||||
IVUsers run(Loop &L, AnalysisManager<Loop> &AM);
|
||||
};
|
||||
|
||||
/// Printer pass for the \c IVUsers for a loop.
|
||||
class IVUsersPrinterPass : public PassInfoMixin<IVUsersPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit IVUsersPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,67 @@
|
||||
//===- IndirectCallPromotionAnalysis.h - Indirect call analysis -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Interface to identify indirect call promotion candidates.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_INDIRECTCALLPROMOTIONANALYSIS_H
|
||||
#define LLVM_ANALYSIS_INDIRECTCALLPROMOTIONANALYSIS_H
|
||||
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Instruction;
|
||||
|
||||
// Class for identifying profitable indirect call promotion candidates when
|
||||
// the indirect-call value profile metadata is available.
|
||||
class ICallPromotionAnalysis {
|
||||
private:
|
||||
// Allocate space to read the profile annotation.
|
||||
std::unique_ptr<InstrProfValueData[]> ValueDataArray;
|
||||
|
||||
// Count is the call count for the direct-call target and
|
||||
// TotalCount is the call count for the indirect-call callsite.
|
||||
// Return true we should promote this indirect-call target.
|
||||
bool isPromotionProfitable(uint64_t Count, uint64_t TotalCount);
|
||||
|
||||
// Returns the number of profitable candidates to promote for the
|
||||
// current ValueDataArray and the given \p Inst.
|
||||
uint32_t getProfitablePromotionCandidates(const Instruction *Inst,
|
||||
uint32_t NumVals,
|
||||
uint64_t TotalCount);
|
||||
|
||||
// Noncopyable
|
||||
ICallPromotionAnalysis(const ICallPromotionAnalysis &other) = delete;
|
||||
ICallPromotionAnalysis &
|
||||
operator=(const ICallPromotionAnalysis &other) = delete;
|
||||
|
||||
public:
|
||||
ICallPromotionAnalysis();
|
||||
|
||||
/// \brief Returns reference to array of InstrProfValueData for the given
|
||||
/// instruction \p I.
|
||||
///
|
||||
/// The \p NumVals, \p TotalCount and \p NumCandidates
|
||||
/// are set to the number of values in the array, the total profile count
|
||||
/// of the indirect call \p I, and the number of profitable candidates
|
||||
/// in the given array (which is sorted in reverse order of profitability).
|
||||
///
|
||||
/// The returned array space is owned by this class, and overwritten on
|
||||
/// subsequent calls.
|
||||
ArrayRef<InstrProfValueData>
|
||||
getPromotionCandidatesForInstruction(const Instruction *I, uint32_t &NumVals,
|
||||
uint64_t &TotalCount,
|
||||
uint32_t &NumCandidates);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
43
contrib/llvm/include/llvm/Analysis/IndirectCallSiteVisitor.h
Normal file
43
contrib/llvm/include/llvm/Analysis/IndirectCallSiteVisitor.h
Normal file
@ -0,0 +1,43 @@
|
||||
//===-- IndirectCallSiteVisitor.h - indirect call-sites visitor -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements defines a visitor class and a helper function that find
|
||||
// all indirect call-sites in a function.
|
||||
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
// Visitor class that finds all indirect call sites.
|
||||
struct PGOIndirectCallSiteVisitor
|
||||
: public InstVisitor<PGOIndirectCallSiteVisitor> {
|
||||
std::vector<Instruction *> IndirectCallInsts;
|
||||
PGOIndirectCallSiteVisitor() {}
|
||||
|
||||
void visitCallSite(CallSite CS) {
|
||||
if (CS.getCalledFunction() || !CS.getCalledValue())
|
||||
return;
|
||||
Instruction *I = CS.getInstruction();
|
||||
if (CallInst *CI = dyn_cast<CallInst>(I)) {
|
||||
if (CI->isInlineAsm())
|
||||
return;
|
||||
}
|
||||
if (isa<Constant>(CS.getCalledValue()))
|
||||
return;
|
||||
IndirectCallInsts.push_back(I);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function that finds all indirect call sites.
|
||||
static inline std::vector<Instruction *> findIndirectCallSites(Function &F) {
|
||||
PGOIndirectCallSiteVisitor ICV;
|
||||
ICV.visit(F);
|
||||
return ICV.IndirectCallInsts;
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ class AssumptionCacheTracker;
|
||||
class CallSite;
|
||||
class DataLayout;
|
||||
class Function;
|
||||
class ProfileSummaryInfo;
|
||||
class TargetTransformInfo;
|
||||
|
||||
namespace InlineConstants {
|
||||
@ -101,25 +102,31 @@ public:
|
||||
/// \brief Get an InlineCost object representing the cost of inlining this
|
||||
/// callsite.
|
||||
///
|
||||
/// Note that threshold is passed into this function. Only costs below the
|
||||
/// threshold are computed with any accuracy. The threshold can be used to
|
||||
/// bound the computation necessary to determine whether the cost is
|
||||
/// Note that a default threshold is passed into this function. This threshold
|
||||
/// could be modified based on callsite's properties and only costs below this
|
||||
/// new threshold are computed with any accuracy. The new threshold can be
|
||||
/// used to bound the computation necessary to determine whether the cost is
|
||||
/// sufficiently low to warrant inlining.
|
||||
///
|
||||
/// Also note that calling this function *dynamically* computes the cost of
|
||||
/// inlining the callsite. It is an expensive, heavyweight call.
|
||||
InlineCost getInlineCost(CallSite CS, int Threshold,
|
||||
InlineCost getInlineCost(CallSite CS, int DefaultThreshold,
|
||||
TargetTransformInfo &CalleeTTI,
|
||||
AssumptionCacheTracker *ACT);
|
||||
AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI);
|
||||
|
||||
/// \brief Get an InlineCost with the callee explicitly specified.
|
||||
/// This allows you to calculate the cost of inlining a function via a
|
||||
/// pointer. This behaves exactly as the version with no explicit callee
|
||||
/// parameter in all other respects.
|
||||
//
|
||||
InlineCost getInlineCost(CallSite CS, Function *Callee, int Threshold,
|
||||
InlineCost getInlineCost(CallSite CS, Function *Callee, int DefaultThreshold,
|
||||
TargetTransformInfo &CalleeTTI,
|
||||
AssumptionCacheTracker *ACT);
|
||||
AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI);
|
||||
|
||||
int computeThresholdFromOptLevels(unsigned OptLevel, unsigned SizeOptLevel);
|
||||
|
||||
/// \brief Return the default value of -inline-threshold.
|
||||
int getDefaultInlineThreshold();
|
||||
|
||||
/// \brief Minimal filter to detect invalid constructs for inlining.
|
||||
bool isInlineViable(Function &Callee);
|
||||
|
@ -46,8 +46,7 @@ namespace llvm {
|
||||
class Type;
|
||||
class Value;
|
||||
|
||||
/// SimplifyAddInst - Given operands for an Add, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Add, fold the result or return null.
|
||||
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -55,8 +54,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifySubInst - Given operands for a Sub, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a Sub, fold the result or return null.
|
||||
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -64,8 +62,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FAdd, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
/// Given operands for an FAdd, fold the result or return null.
|
||||
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -73,8 +70,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FSub, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
/// Given operands for an FSub, fold the result or return null.
|
||||
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -82,8 +78,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FMul, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
/// Given operands for an FMul, fold the result or return null.
|
||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -91,32 +86,28 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyMulInst - Given operands for a Mul, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a Mul, fold the result or return null.
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifySDivInst - Given operands for an SDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an SDiv, fold the result or return null.
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a UDiv, fold the result or return null.
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyFDivInst - Given operands for an FDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an FDiv, fold the result or return null.
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -124,24 +115,21 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifySRemInst - Given operands for an SRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an SRem, fold the result or return null.
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyURemInst - Given operands for a URem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a URem, fold the result or return null.
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyFRemInst - Given operands for an FRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an FRem, fold the result or return null.
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -149,8 +137,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyShlInst - Given operands for a Shl, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a Shl, fold the result or return null.
|
||||
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -158,8 +145,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyLShrInst - Given operands for a LShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a LShr, fold the result or return null.
|
||||
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -167,8 +153,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyAShrInst - Given operands for a AShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a AShr, fold the result or return nulll.
|
||||
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -176,32 +161,28 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyAndInst - Given operands for an And, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an And, fold the result or return null.
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyOrInst - Given operands for an Or, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Or, fold the result or return null.
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyXorInst - Given operands for a Xor, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Xor, fold the result or return null.
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an ICmpInst, fold the result or return null.
|
||||
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -209,8 +190,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an FCmpInst, fold the result or return null.
|
||||
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -218,8 +198,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
/// Given operands for a SelectInst, fold the result or return null.
|
||||
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -227,16 +206,15 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout &DL,
|
||||
/// Given operands for a GetElementPtrInst, fold the result or return null.
|
||||
Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
|
||||
/// can fold the result. If not, this returns null.
|
||||
/// Given operands for an InsertValueInst, fold the result or return null.
|
||||
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||
ArrayRef<unsigned> Idxs, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -244,8 +222,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// \brief Given operands for an ExtractValueInst, see if we can fold the
|
||||
/// result. If not, this returns null.
|
||||
/// Given operands for an ExtractValueInst, fold the result or return null.
|
||||
Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -253,8 +230,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// \brief Given operands for an ExtractElementInst, see if we can fold the
|
||||
/// result. If not, this returns null.
|
||||
/// Given operands for an ExtractElementInst, fold the result or return null.
|
||||
Value *SimplifyExtractElementInst(Value *Vec, Value *Idx,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -262,8 +238,7 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyTruncInst - Given operands for an TruncInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
/// Given operands for an TruncInst, fold the result or return null.
|
||||
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
@ -273,8 +248,7 @@ namespace llvm {
|
||||
//=== Helper functions for higher up the class hierarchy.
|
||||
|
||||
|
||||
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a CmpInst, fold the result or return null.
|
||||
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -282,16 +256,15 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a BinaryOperator, fold the result or return null.
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
/// SimplifyFPBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
|
||||
/// Given operands for an FP BinaryOperator, fold the result or return null.
|
||||
/// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the
|
||||
/// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp.
|
||||
Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
@ -301,10 +274,8 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// \brief Given a function and iterators over arguments, see if we can fold
|
||||
/// the result.
|
||||
///
|
||||
/// If this call could not be simplified returns null.
|
||||
/// Given a function and iterators over arguments, fold the result or return
|
||||
/// null.
|
||||
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
||||
User::op_iterator ArgEnd, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
@ -312,25 +283,21 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// \brief Given a function and set of arguments, see if we can fold the
|
||||
/// result.
|
||||
///
|
||||
/// If this call could not be simplified returns null.
|
||||
/// Given a function and set of arguments, fold the result or return null.
|
||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// SimplifyInstruction - See if we can compute a simplified version of this
|
||||
/// instruction. If not, this returns null.
|
||||
/// See if we can compute a simplified version of this instruction. If not,
|
||||
/// return null.
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
|
||||
/// \brief Replace all uses of 'I' with 'SimpleV' and simplify the uses
|
||||
/// recursively.
|
||||
/// Replace all uses of 'I' with 'SimpleV' and simplify the uses recursively.
|
||||
///
|
||||
/// This first performs a normal RAUW of I with SimpleV. It then recursively
|
||||
/// attempts to simplify those users updated by the operation. The 'I'
|
||||
@ -342,7 +309,7 @@ namespace llvm {
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
|
||||
/// \brief Recursively attempt to simplify an instruction.
|
||||
/// Recursively attempt to simplify an instruction.
|
||||
///
|
||||
/// This routine uses SimplifyInstruction to simplify 'I', and if successful
|
||||
/// replaces uses of 'I' with the simplified value. It then recurses on each
|
||||
|
@ -67,8 +67,9 @@ public:
|
||||
|
||||
/// contains - Find out if a basic block is in this interval
|
||||
inline bool contains(BasicBlock *BB) const {
|
||||
for (unsigned i = 0; i < Nodes.size(); ++i)
|
||||
if (Nodes[i] == BB) return true;
|
||||
for (BasicBlock *Node : Nodes)
|
||||
if (Node == BB)
|
||||
return true;
|
||||
return false;
|
||||
// I don't want the dependency on <algorithm>
|
||||
//return find(Nodes.begin(), Nodes.end(), BB) != Nodes.end();
|
||||
@ -76,8 +77,9 @@ public:
|
||||
|
||||
/// isSuccessor - find out if a basic block is a successor of this Interval
|
||||
inline bool isSuccessor(BasicBlock *BB) const {
|
||||
for (unsigned i = 0; i < Successors.size(); ++i)
|
||||
if (Successors[i] == BB) return true;
|
||||
for (BasicBlock *Successor : Successors)
|
||||
if (Successor == BB)
|
||||
return true;
|
||||
return false;
|
||||
// I don't want the dependency on <algorithm>
|
||||
//return find(Successors.begin(), Successors.end(), BB) != Successors.end();
|
||||
|
@ -24,18 +24,14 @@
|
||||
#ifndef LLVM_ANALYSIS_IDF_H
|
||||
#define LLVM_ANALYSIS_IDF_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BasicBlock;
|
||||
template <class T> class DomTreeNodeBase;
|
||||
typedef DomTreeNodeBase<BasicBlock> DomTreeNode;
|
||||
template <class T> class DominatorTreeBase;
|
||||
|
||||
/// \brief Determine the iterated dominance frontier, given a set of defining
|
||||
/// blocks, and optionally, a set of live-in blocks.
|
||||
///
|
||||
@ -44,6 +40,9 @@ template <class T> class DominatorTreeBase;
|
||||
/// This algorithm is a linear time computation of Iterated Dominance Frontiers,
|
||||
/// pruned using the live-in set.
|
||||
/// By default, liveness is not used to prune the IDF computation.
|
||||
/// The template parameters should be either BasicBlock* or Inverse<BasicBlock
|
||||
/// *>, depending on if you want the forward or reverse IDF.
|
||||
template <class NodeTy>
|
||||
class IDFCalculator {
|
||||
|
||||
public:
|
||||
@ -92,5 +91,7 @@ private:
|
||||
const SmallPtrSetImpl<BasicBlock *> *DefBlocks;
|
||||
SmallVector<BasicBlock *, 32> PHIBlocks;
|
||||
};
|
||||
typedef IDFCalculator<BasicBlock *> ForwardIDFCalculator;
|
||||
typedef IDFCalculator<Inverse<BasicBlock *>> ReverseIDFCalculator;
|
||||
}
|
||||
#endif
|
||||
|
125
contrib/llvm/include/llvm/Analysis/LazyBlockFrequencyInfo.h
Normal file
125
contrib/llvm/include/llvm/Analysis/LazyBlockFrequencyInfo.h
Normal file
@ -0,0 +1,125 @@
|
||||
//===- LazyBlockFrequencyInfo.h - Lazy Block Frequency Analysis -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is an alternative analysis pass to BlockFrequencyInfoWrapperPass. The
|
||||
// difference is that with this pass the block frequencies are not computed when
|
||||
// the analysis pass is executed but rather when the BFI results is explicitly
|
||||
// requested by the analysis client.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H
|
||||
#define LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H
|
||||
|
||||
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
class AnalysisUsage;
|
||||
class BranchProbabilityInfo;
|
||||
class Function;
|
||||
class LoopInfo;
|
||||
|
||||
/// \brief This is an alternative analysis pass to
|
||||
/// BlockFrequencyInfoWrapperPass. The difference is that with this pass the
|
||||
/// block frequencies are not computed when the analysis pass is executed but
|
||||
/// rather when the BFI results is explicitly requested by the analysis client.
|
||||
///
|
||||
/// There are some additional requirements for any client pass that wants to use
|
||||
/// the analysis:
|
||||
///
|
||||
/// 1. The pass needs to initialize dependent passes with:
|
||||
///
|
||||
/// INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)
|
||||
///
|
||||
/// 2. Similarly, getAnalysisUsage should call:
|
||||
///
|
||||
/// LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU)
|
||||
///
|
||||
/// 3. The computed BFI should be requested with
|
||||
/// getAnalysis<LazyBlockFrequencyInfoPass>().getBFI() before either LoopInfo
|
||||
/// or BPI could be invalidated for example by changing the CFG.
|
||||
///
|
||||
/// Note that it is expected that we wouldn't need this functionality for the
|
||||
/// new PM since with the new PM, analyses are executed on demand.
|
||||
class LazyBlockFrequencyInfoPass : public FunctionPass {
|
||||
|
||||
/// Wraps a BFI to allow lazy computation of the block frequencies.
|
||||
///
|
||||
/// A pass that only conditionally uses BFI can uncondtionally require the
|
||||
/// analysis without paying for the overhead if BFI doesn't end up being used.
|
||||
class LazyBlockFrequencyInfo {
|
||||
public:
|
||||
LazyBlockFrequencyInfo()
|
||||
: Calculated(false), F(nullptr), BPI(nullptr), LI(nullptr) {}
|
||||
|
||||
/// Set up the per-function input.
|
||||
void setAnalysis(const Function *F, const BranchProbabilityInfo *BPI,
|
||||
const LoopInfo *LI) {
|
||||
this->F = F;
|
||||
this->BPI = BPI;
|
||||
this->LI = LI;
|
||||
}
|
||||
|
||||
/// Retrieve the BFI with the block frequencies computed.
|
||||
BlockFrequencyInfo &getCalculated() {
|
||||
if (!Calculated) {
|
||||
assert(F && BPI && LI && "call setAnalysis");
|
||||
BFI.calculate(*F, *BPI, *LI);
|
||||
Calculated = true;
|
||||
}
|
||||
return BFI;
|
||||
}
|
||||
|
||||
const BlockFrequencyInfo &getCalculated() const {
|
||||
return const_cast<LazyBlockFrequencyInfo *>(this)->getCalculated();
|
||||
}
|
||||
|
||||
void releaseMemory() {
|
||||
BFI.releaseMemory();
|
||||
Calculated = false;
|
||||
setAnalysis(nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
BlockFrequencyInfo BFI;
|
||||
bool Calculated;
|
||||
const Function *F;
|
||||
const BranchProbabilityInfo *BPI;
|
||||
const LoopInfo *LI;
|
||||
};
|
||||
|
||||
LazyBlockFrequencyInfo LBFI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LazyBlockFrequencyInfoPass();
|
||||
|
||||
/// \brief Compute and return the block frequencies.
|
||||
BlockFrequencyInfo &getBFI() { return LBFI.getCalculated(); }
|
||||
|
||||
/// \brief Compute and return the block frequencies.
|
||||
const BlockFrequencyInfo &getBFI() const { return LBFI.getCalculated(); }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// Helper for client passes to set up the analysis usage on behalf of this
|
||||
/// pass.
|
||||
static void getLazyBFIAnalysisUsage(AnalysisUsage &AU);
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
void releaseMemory() override;
|
||||
void print(raw_ostream &OS, const Module *M) const override;
|
||||
};
|
||||
|
||||
/// \brief Helper for client passes to initialize dependent passes for LBFI.
|
||||
void initializeLazyBFIPassPass(PassRegistry &Registry);
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -15,11 +15,13 @@
|
||||
#ifndef LLVM_ANALYSIS_LAZYVALUEINFO_H
|
||||
#define LLVM_ANALYSIS_LAZYVALUEINFO_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
class AssumptionCache;
|
||||
class Constant;
|
||||
class ConstantRange;
|
||||
class DataLayout;
|
||||
class DominatorTree;
|
||||
class Instruction;
|
||||
@ -27,19 +29,33 @@ namespace llvm {
|
||||
class Value;
|
||||
|
||||
/// This pass computes, caches, and vends lazy value constraint information.
|
||||
class LazyValueInfo : public FunctionPass {
|
||||
AssumptionCache *AC;
|
||||
class TargetLibraryInfo *TLI;
|
||||
DominatorTree *DT;
|
||||
void *PImpl;
|
||||
class LazyValueInfo {
|
||||
friend class LazyValueInfoWrapperPass;
|
||||
AssumptionCache *AC = nullptr;
|
||||
class TargetLibraryInfo *TLI = nullptr;
|
||||
DominatorTree *DT = nullptr;
|
||||
void *PImpl = nullptr;
|
||||
LazyValueInfo(const LazyValueInfo&) = delete;
|
||||
void operator=(const LazyValueInfo&) = delete;
|
||||
public:
|
||||
static char ID;
|
||||
LazyValueInfo() : FunctionPass(ID), PImpl(nullptr) {
|
||||
initializeLazyValueInfoPass(*PassRegistry::getPassRegistry());
|
||||
~LazyValueInfo();
|
||||
LazyValueInfo() {}
|
||||
LazyValueInfo(AssumptionCache *AC_, TargetLibraryInfo *TLI_,
|
||||
DominatorTree *DT_)
|
||||
: AC(AC_), TLI(TLI_), DT(DT_) {}
|
||||
LazyValueInfo(LazyValueInfo &&Arg)
|
||||
: AC(Arg.AC), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) {
|
||||
Arg.PImpl = nullptr;
|
||||
}
|
||||
LazyValueInfo &operator=(LazyValueInfo &&Arg) {
|
||||
releaseMemory();
|
||||
AC = Arg.AC;
|
||||
TLI = Arg.TLI;
|
||||
DT = Arg.DT;
|
||||
PImpl = Arg.PImpl;
|
||||
Arg.PImpl = nullptr;
|
||||
return *this;
|
||||
}
|
||||
~LazyValueInfo() override { assert(!PImpl && "releaseMemory not called"); }
|
||||
|
||||
/// This is used to return true/false/dunno results.
|
||||
enum Tristate {
|
||||
@ -65,6 +81,11 @@ public:
|
||||
/// constant at the end of the specified block. Return null if not.
|
||||
Constant *getConstant(Value *V, BasicBlock *BB, Instruction *CxtI = nullptr);
|
||||
|
||||
/// Return the ConstantRange constraint that is known to hold for the
|
||||
/// specified value at the end of the specified block. This may only be called
|
||||
/// on integer-typed Values.
|
||||
ConstantRange getConstantRange(Value *V, BasicBlock *BB, Instruction *CxtI = nullptr);
|
||||
|
||||
/// Determine whether the specified value is known to be a
|
||||
/// constant on the specified edge. Return null if not.
|
||||
Constant *getConstantOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB,
|
||||
@ -77,11 +98,41 @@ public:
|
||||
/// Inform the analysis cache that we have erased a block.
|
||||
void eraseBlock(BasicBlock *BB);
|
||||
|
||||
// Implementation boilerplate.
|
||||
// For old PM pass. Delete once LazyValueInfoWrapperPass is gone.
|
||||
void releaseMemory();
|
||||
};
|
||||
|
||||
/// \brief Analysis to compute lazy value information.
|
||||
class LazyValueAnalysis : public AnalysisInfoMixin<LazyValueAnalysis> {
|
||||
public:
|
||||
typedef LazyValueInfo Result;
|
||||
Result run(Function &F, FunctionAnalysisManager &FAM);
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
friend struct AnalysisInfoMixin<LazyValueAnalysis>;
|
||||
};
|
||||
|
||||
/// Wrapper around LazyValueInfo.
|
||||
class LazyValueInfoWrapperPass : public FunctionPass {
|
||||
LazyValueInfoWrapperPass(const LazyValueInfoWrapperPass&) = delete;
|
||||
void operator=(const LazyValueInfoWrapperPass&) = delete;
|
||||
public:
|
||||
static char ID;
|
||||
LazyValueInfoWrapperPass() : FunctionPass(ID) {
|
||||
initializeLazyValueInfoWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
~LazyValueInfoWrapperPass() override {
|
||||
assert(!Info.PImpl && "releaseMemory not called");
|
||||
}
|
||||
|
||||
LazyValueInfo &getLVI();
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
void releaseMemory() override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
private:
|
||||
LazyValueInfo Info;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -23,39 +23,74 @@ namespace llvm {
|
||||
class DataLayout;
|
||||
class MDNode;
|
||||
|
||||
/// isDereferenceablePointer - Return true if this is always a dereferenceable
|
||||
/// pointer. If the context instruction is specified perform context-sensitive
|
||||
/// analysis and return true if the pointer is dereferenceable at the
|
||||
/// specified instruction.
|
||||
bool isDereferenceablePointer(const Value *V, const DataLayout &DL,
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// Returns true if V is always a dereferenceable pointer with alignment
|
||||
/// greater or equal than requested. If the context instruction is specified
|
||||
/// performs context-sensitive analysis and returns true if the pointer is
|
||||
/// dereferenceable at the specified instruction.
|
||||
bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align,
|
||||
const DataLayout &DL,
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// isSafeToLoadUnconditionally - Return true if we know that executing a load
|
||||
/// from this value cannot trap. If it is not obviously safe to load from the
|
||||
/// specified pointer, we do a quick local scan of the basic block containing
|
||||
/// ScanFrom, to determine if the address is already accessed.
|
||||
bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
|
||||
unsigned Align);
|
||||
/// from this value cannot trap.
|
||||
///
|
||||
/// If DT and ScanFrom are specified this method performs context-sensitive
|
||||
/// analysis and returns true if it is safe to load immediately before ScanFrom.
|
||||
///
|
||||
/// If it is not obviously safe to load from the specified pointer, we do a
|
||||
/// quick local scan of the basic block containing ScanFrom, to determine if
|
||||
/// the address is already accessed.
|
||||
bool isSafeToLoadUnconditionally(Value *V, unsigned Align,
|
||||
const DataLayout &DL,
|
||||
Instruction *ScanFrom = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// DefMaxInstsToScan - the default number of maximum instructions
|
||||
/// to scan in the block, used by FindAvailableLoadedValue().
|
||||
extern cl::opt<unsigned> DefMaxInstsToScan;
|
||||
|
||||
/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at
|
||||
/// the instruction before ScanFrom) checking to see if we have the value at
|
||||
/// the memory address *Ptr locally available within a small number of
|
||||
/// instructions. If the value is available, return it.
|
||||
/// \brief Scan backwards to see if we have the value of the given load
|
||||
/// available locally within a small number of instructions.
|
||||
///
|
||||
/// If not, return the iterator for the last validated instruction that the
|
||||
/// value would be live through. If we scanned the entire block and didn't
|
||||
/// find something that invalidates *Ptr or provides it, ScanFrom would be
|
||||
/// left at begin() and this returns null. ScanFrom could also be left
|
||||
/// You can use this function to scan across multiple blocks: after you call
|
||||
/// this function, if ScanFrom points at the beginning of the block, it's safe
|
||||
/// to continue scanning the predecessors.
|
||||
///
|
||||
/// MaxInstsToScan specifies the maximum instructions to scan in the block.
|
||||
/// If it is set to 0, it will scan the whole block. You can also optionally
|
||||
/// specify an alias analysis implementation, which makes this more precise.
|
||||
/// Note that performing load CSE requires special care to make sure the
|
||||
/// metadata is set appropriately. In particular, aliasing metadata needs
|
||||
/// to be merged. (This doesn't matter for store-to-load forwarding because
|
||||
/// the only relevant load gets deleted.)
|
||||
///
|
||||
/// If AATags is non-null and a load or store is found, the AA tags from the
|
||||
/// load or store are recorded there. If there are no AA tags or if no access
|
||||
/// is found, it is left unmodified.
|
||||
Value *FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB,
|
||||
/// \param Load The load we want to replace.
|
||||
/// \param ScanBB The basic block to scan. FIXME: This is redundant.
|
||||
/// \param [in,out] ScanFrom The location to start scanning from. When this
|
||||
/// function returns, it points at the last instruction scanned.
|
||||
/// \param MaxInstsToScan The maximum number of instructions to scan. If this
|
||||
/// is zero, the whole block will be scanned.
|
||||
/// \param AA Optional pointer to alias analysis, to make the scan more
|
||||
/// precise.
|
||||
/// \param [out] AATags The aliasing metadata for the operation which produced
|
||||
/// the value. FIXME: This is basically useless.
|
||||
/// \param [out] IsLoadCSE Whether the returned value is a load from the same
|
||||
/// location in memory, as opposed to the value operand of a store.
|
||||
///
|
||||
/// \returns The found value, or nullptr if no value is found.
|
||||
Value *FindAvailableLoadedValue(LoadInst *Load,
|
||||
BasicBlock *ScanBB,
|
||||
BasicBlock::iterator &ScanFrom,
|
||||
unsigned MaxInstsToScan = DefMaxInstsToScan,
|
||||
AliasAnalysis *AA = nullptr,
|
||||
AAMDNodes *AATags = nullptr);
|
||||
AAMDNodes *AATags = nullptr,
|
||||
bool *IsLoadCSE = nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ public:
|
||||
|
||||
/// \brief The maximum number of bytes of a vector register we can vectorize
|
||||
/// the accesses safely with.
|
||||
unsigned getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; }
|
||||
uint64_t getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; }
|
||||
|
||||
/// \brief In same cases when the dependency check fails we can still
|
||||
/// vectorize the loop with a dynamic array access check.
|
||||
@ -284,7 +284,7 @@ private:
|
||||
unsigned AccessIdx;
|
||||
|
||||
// We can access this many bytes in parallel safely.
|
||||
unsigned MaxSafeDepDistBytes;
|
||||
uint64_t MaxSafeDepDistBytes;
|
||||
|
||||
/// \brief If we see a non-constant dependence distance we can still try to
|
||||
/// vectorize this loop with runtime checks.
|
||||
@ -321,7 +321,10 @@ private:
|
||||
|
||||
/// \brief Check whether the data dependence could prevent store-load
|
||||
/// forwarding.
|
||||
bool couldPreventStoreLoadForward(unsigned Distance, unsigned TypeByteSize);
|
||||
///
|
||||
/// \return false if we shouldn't vectorize at all or avoid larger
|
||||
/// vectorization factors by limiting MaxSafeDepDistBytes.
|
||||
bool couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize);
|
||||
};
|
||||
|
||||
/// \brief Holds information about the memory runtime legality checks to verify
|
||||
@ -363,10 +366,10 @@ public:
|
||||
}
|
||||
|
||||
/// Insert a pointer and calculate the start and end SCEVs.
|
||||
/// \p We need Preds in order to compute the SCEV expression of the pointer
|
||||
/// We need \p PSE in order to compute the SCEV expression of the pointer
|
||||
/// according to the assumptions that we've made during the analysis.
|
||||
/// The method might also version the pointer stride according to \p Strides,
|
||||
/// and change \p Preds.
|
||||
/// and add new predicates to \p PSE.
|
||||
void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId,
|
||||
unsigned ASId, const ValueToValueMap &Strides,
|
||||
PredicatedScalarEvolution &PSE);
|
||||
@ -508,23 +511,53 @@ private:
|
||||
/// PSE must be emitted in order for the results of this analysis to be valid.
|
||||
class LoopAccessInfo {
|
||||
public:
|
||||
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI, AliasAnalysis *AA,
|
||||
DominatorTree *DT, LoopInfo *LI,
|
||||
const ValueToValueMap &Strides);
|
||||
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const TargetLibraryInfo *TLI,
|
||||
AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI);
|
||||
|
||||
// FIXME:
|
||||
// Hack for MSVC 2013 which sems like it can't synthesize this even
|
||||
// with default keyword:
|
||||
// LoopAccessInfo(LoopAccessInfo &&LAI) = default;
|
||||
LoopAccessInfo(LoopAccessInfo &&LAI)
|
||||
: PSE(std::move(LAI.PSE)), PtrRtChecking(std::move(LAI.PtrRtChecking)),
|
||||
DepChecker(std::move(LAI.DepChecker)), TheLoop(LAI.TheLoop),
|
||||
NumLoads(LAI.NumLoads), NumStores(LAI.NumStores),
|
||||
MaxSafeDepDistBytes(LAI.MaxSafeDepDistBytes), CanVecMem(LAI.CanVecMem),
|
||||
StoreToLoopInvariantAddress(LAI.StoreToLoopInvariantAddress),
|
||||
Report(std::move(LAI.Report)),
|
||||
SymbolicStrides(std::move(LAI.SymbolicStrides)),
|
||||
StrideSet(std::move(LAI.StrideSet)) {}
|
||||
// LoopAccessInfo &operator=(LoopAccessInfo &&LAI) = default;
|
||||
LoopAccessInfo &operator=(LoopAccessInfo &&LAI) {
|
||||
assert(this != &LAI);
|
||||
|
||||
PSE = std::move(LAI.PSE);
|
||||
PtrRtChecking = std::move(LAI.PtrRtChecking);
|
||||
DepChecker = std::move(LAI.DepChecker);
|
||||
TheLoop = LAI.TheLoop;
|
||||
NumLoads = LAI.NumLoads;
|
||||
NumStores = LAI.NumStores;
|
||||
MaxSafeDepDistBytes = LAI.MaxSafeDepDistBytes;
|
||||
CanVecMem = LAI.CanVecMem;
|
||||
StoreToLoopInvariantAddress = LAI.StoreToLoopInvariantAddress;
|
||||
Report = std::move(LAI.Report);
|
||||
SymbolicStrides = std::move(LAI.SymbolicStrides);
|
||||
StrideSet = std::move(LAI.StrideSet);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return true we can analyze the memory accesses in the loop and there are
|
||||
/// no memory dependence cycles.
|
||||
bool canVectorizeMemory() const { return CanVecMem; }
|
||||
|
||||
const RuntimePointerChecking *getRuntimePointerChecking() const {
|
||||
return &PtrRtChecking;
|
||||
return PtrRtChecking.get();
|
||||
}
|
||||
|
||||
/// \brief Number of memchecks required to prove independence of otherwise
|
||||
/// may-alias pointers.
|
||||
unsigned getNumRuntimePointerChecks() const {
|
||||
return PtrRtChecking.getNumberOfChecks();
|
||||
return PtrRtChecking->getNumberOfChecks();
|
||||
}
|
||||
|
||||
/// Return true if the block BB needs to be predicated in order for the loop
|
||||
@ -535,7 +568,7 @@ public:
|
||||
/// Returns true if the value V is uniform within the loop.
|
||||
bool isUniform(Value *V) const;
|
||||
|
||||
unsigned getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; }
|
||||
uint64_t getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; }
|
||||
unsigned getNumStores() const { return NumStores; }
|
||||
unsigned getNumLoads() const { return NumLoads;}
|
||||
|
||||
@ -563,23 +596,25 @@ public:
|
||||
|
||||
/// \brief the Memory Dependence Checker which can determine the
|
||||
/// loop-independent and loop-carried dependences between memory accesses.
|
||||
const MemoryDepChecker &getDepChecker() const { return DepChecker; }
|
||||
const MemoryDepChecker &getDepChecker() const { return *DepChecker; }
|
||||
|
||||
/// \brief Return the list of instructions that use \p Ptr to read or write
|
||||
/// memory.
|
||||
SmallVector<Instruction *, 4> getInstructionsForAccess(Value *Ptr,
|
||||
bool isWrite) const {
|
||||
return DepChecker.getInstructionsForAccess(Ptr, isWrite);
|
||||
return DepChecker->getInstructionsForAccess(Ptr, isWrite);
|
||||
}
|
||||
|
||||
/// \brief If an access has a symbolic strides, this maps the pointer value to
|
||||
/// the stride symbol.
|
||||
const ValueToValueMap &getSymbolicStrides() const { return SymbolicStrides; }
|
||||
|
||||
/// \brief Pointer has a symbolic stride.
|
||||
bool hasStride(Value *V) const { return StrideSet.count(V); }
|
||||
|
||||
/// \brief Print the information about the memory accesses in the loop.
|
||||
void print(raw_ostream &OS, unsigned Depth = 0) const;
|
||||
|
||||
/// \brief Used to ensure that if the analysis was run with speculating the
|
||||
/// value of symbolic strides, the client queries it with the same assumption.
|
||||
/// Only used in DEBUG build but we don't want NDEBUG-dependent ABI.
|
||||
unsigned NumSymbolicStrides;
|
||||
|
||||
/// \brief Checks existence of store to invariant address inside loop.
|
||||
/// If the loop has any store to invariant address, then it returns true,
|
||||
/// else returns false.
|
||||
@ -592,11 +627,12 @@ public:
|
||||
/// should be re-written (and therefore simplified) according to PSE.
|
||||
/// A user of LoopAccessAnalysis will need to emit the runtime checks
|
||||
/// associated with this predicate.
|
||||
PredicatedScalarEvolution PSE;
|
||||
const PredicatedScalarEvolution &getPSE() const { return *PSE; }
|
||||
|
||||
private:
|
||||
/// \brief Analyze the loop. Substitute symbolic strides using Strides.
|
||||
void analyzeLoop(const ValueToValueMap &Strides);
|
||||
/// \brief Analyze the loop.
|
||||
void analyzeLoop(AliasAnalysis *AA, LoopInfo *LI,
|
||||
const TargetLibraryInfo *TLI, DominatorTree *DT);
|
||||
|
||||
/// \brief Check if the structure of the loop allows it to be analyzed by this
|
||||
/// pass.
|
||||
@ -604,25 +640,28 @@ private:
|
||||
|
||||
void emitAnalysis(LoopAccessReport &Message);
|
||||
|
||||
/// \brief Collect memory access with loop invariant strides.
|
||||
///
|
||||
/// Looks for accesses like "a[i * StrideA]" where "StrideA" is loop
|
||||
/// invariant.
|
||||
void collectStridedAccess(Value *LoadOrStoreInst);
|
||||
|
||||
std::unique_ptr<PredicatedScalarEvolution> PSE;
|
||||
|
||||
/// We need to check that all of the pointers in this list are disjoint
|
||||
/// at runtime.
|
||||
RuntimePointerChecking PtrRtChecking;
|
||||
/// at runtime. Using std::unique_ptr to make using move ctor simpler.
|
||||
std::unique_ptr<RuntimePointerChecking> PtrRtChecking;
|
||||
|
||||
/// \brief the Memory Dependence Checker which can determine the
|
||||
/// loop-independent and loop-carried dependences between memory accesses.
|
||||
MemoryDepChecker DepChecker;
|
||||
std::unique_ptr<MemoryDepChecker> DepChecker;
|
||||
|
||||
Loop *TheLoop;
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
AliasAnalysis *AA;
|
||||
DominatorTree *DT;
|
||||
LoopInfo *LI;
|
||||
|
||||
unsigned NumLoads;
|
||||
unsigned NumStores;
|
||||
|
||||
unsigned MaxSafeDepDistBytes;
|
||||
uint64_t MaxSafeDepDistBytes;
|
||||
|
||||
/// \brief Cache the result of analyzeLoop.
|
||||
bool CanVecMem;
|
||||
@ -634,15 +673,23 @@ private:
|
||||
/// \brief The diagnostics report generated for the analysis. E.g. why we
|
||||
/// couldn't analyze the loop.
|
||||
Optional<LoopAccessReport> Report;
|
||||
|
||||
/// \brief If an access has a symbolic strides, this maps the pointer value to
|
||||
/// the stride symbol.
|
||||
ValueToValueMap SymbolicStrides;
|
||||
|
||||
/// \brief Set of symbolic strides values.
|
||||
SmallPtrSet<Value *, 8> StrideSet;
|
||||
};
|
||||
|
||||
Value *stripIntegerCast(Value *V);
|
||||
|
||||
///\brief Return the SCEV corresponding to a pointer with the symbolic stride
|
||||
/// replaced with constant one, assuming \p Preds is true.
|
||||
/// \brief Return the SCEV corresponding to a pointer with the symbolic stride
|
||||
/// replaced with constant one, assuming the SCEV predicate associated with
|
||||
/// \p PSE is true.
|
||||
///
|
||||
/// If necessary this method will version the stride of the pointer according
|
||||
/// to \p PtrToStride and therefore add a new predicate to \p Preds.
|
||||
/// to \p PtrToStride and therefore add further predicates to \p PSE.
|
||||
///
|
||||
/// If \p OrigPtr is not null, use it to look up the stride value instead of \p
|
||||
/// Ptr. \p PtrToStride provides the mapping between the pointer value and its
|
||||
@ -651,13 +698,24 @@ const SCEV *replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
|
||||
const ValueToValueMap &PtrToStride,
|
||||
Value *Ptr, Value *OrigPtr = nullptr);
|
||||
|
||||
/// \brief Check the stride of the pointer and ensure that it does not wrap in
|
||||
/// the address space, assuming \p Preds is true.
|
||||
/// \brief If the pointer has a constant stride return it in units of its
|
||||
/// element size. Otherwise return zero.
|
||||
///
|
||||
/// Ensure that it does not wrap in the address space, assuming the predicate
|
||||
/// associated with \p PSE is true.
|
||||
///
|
||||
/// If necessary this method will version the stride of the pointer according
|
||||
/// to \p PtrToStride and therefore add a new predicate to \p Preds.
|
||||
int isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
|
||||
const ValueToValueMap &StridesMap);
|
||||
/// to \p PtrToStride and therefore add further predicates to \p PSE.
|
||||
/// The \p Assume parameter indicates if we are allowed to make additional
|
||||
/// run-time assumptions.
|
||||
int64_t getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
|
||||
const ValueToValueMap &StridesMap = ValueToValueMap(),
|
||||
bool Assume = false);
|
||||
|
||||
/// \brief Returns true if the memory operations \p A and \p B are consecutive.
|
||||
/// This is a simple API that does not depend on the analysis pass.
|
||||
bool isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL,
|
||||
ScalarEvolution &SE, bool CheckType = true);
|
||||
|
||||
/// \brief This analysis provides dependence information for the memory accesses
|
||||
/// of a loop.
|
||||
@ -666,12 +724,12 @@ int isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
|
||||
/// querying the loop access info via LAA::getInfo. getInfo return a
|
||||
/// LoopAccessInfo object. See this class for the specifics of what information
|
||||
/// is provided.
|
||||
class LoopAccessAnalysis : public FunctionPass {
|
||||
class LoopAccessLegacyAnalysis : public FunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LoopAccessAnalysis() : FunctionPass(ID) {
|
||||
initializeLoopAccessAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
LoopAccessLegacyAnalysis() : FunctionPass(ID) {
|
||||
initializeLoopAccessLegacyAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
@ -680,11 +738,8 @@ public:
|
||||
|
||||
/// \brief Query the result of the loop access information for the loop \p L.
|
||||
///
|
||||
/// If the client speculates (and then issues run-time checks) for the values
|
||||
/// of symbolic strides, \p Strides provides the mapping (see
|
||||
/// replaceSymbolicStrideSCEV). If there is no cached result available run
|
||||
/// the analysis.
|
||||
const LoopAccessInfo &getInfo(Loop *L, const ValueToValueMap &Strides);
|
||||
/// If there is no cached result available run the analysis.
|
||||
const LoopAccessInfo &getInfo(Loop *L);
|
||||
|
||||
void releaseMemory() override {
|
||||
// Invalidate the cache when the pass is freed.
|
||||
@ -706,6 +761,34 @@ private:
|
||||
LoopInfo *LI;
|
||||
};
|
||||
|
||||
/// \brief This analysis provides dependence information for the memory
|
||||
/// accesses of a loop.
|
||||
///
|
||||
/// It runs the analysis for a loop on demand. This can be initiated by
|
||||
/// querying the loop access info via AM.getResult<LoopAccessAnalysis>.
|
||||
/// getResult return a LoopAccessInfo object. See this class for the
|
||||
/// specifics of what information is provided.
|
||||
class LoopAccessAnalysis
|
||||
: public AnalysisInfoMixin<LoopAccessAnalysis> {
|
||||
friend AnalysisInfoMixin<LoopAccessAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef LoopAccessInfo Result;
|
||||
Result run(Loop &, AnalysisManager<Loop> &);
|
||||
static StringRef name() { return "LoopAccessAnalysis"; }
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c LoopAccessInfo results.
|
||||
class LoopAccessInfoPrinterPass
|
||||
: public PassInfoMixin<LoopAccessInfoPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit LoopAccessInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM);
|
||||
};
|
||||
|
||||
inline Instruction *MemoryDepChecker::Dependence::getSource(
|
||||
const LoopAccessInfo &LAI) const {
|
||||
return LAI.getDepChecker().getMemoryInstructions()[Source];
|
||||
|
@ -25,6 +25,12 @@
|
||||
// * the loop depth
|
||||
// * etc...
|
||||
//
|
||||
// Note that this analysis specifically identifies *Loops* not cycles or SCCs
|
||||
// in the CFG. There can be strongly connected compontents in the CFG which
|
||||
// this analysis will not recognize and that will not be represented by a Loop
|
||||
// instance. In particular, a Loop might be inside such a non-loop SCC, or a
|
||||
// non-loop SCC might contain a sub-SCC which is a Loop.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPINFO_H
|
||||
@ -38,16 +44,12 @@
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// FIXME: Replace this brittle forward declaration with the include of the new
|
||||
// PassManager.h when doing so doesn't break the PassManagerBuilder.
|
||||
template <typename IRUnitT> class AnalysisManager;
|
||||
class PreservedAnalyses;
|
||||
|
||||
class DominatorTree;
|
||||
class LoopInfo;
|
||||
class Loop;
|
||||
@ -346,6 +348,9 @@ raw_ostream& operator<<(raw_ostream &OS, const LoopBase<BlockT, LoopT> &Loop) {
|
||||
// Implementation in LoopInfoImpl.h
|
||||
extern template class LoopBase<BasicBlock, Loop>;
|
||||
|
||||
|
||||
/// Represents a single loop in the control flow graph. Note that not all SCCs
|
||||
/// in the CFG are neccessarily loops.
|
||||
class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
public:
|
||||
Loop() {}
|
||||
@ -452,21 +457,13 @@ public:
|
||||
/// 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 {
|
||||
BasicBlock *HeadBB;
|
||||
DebugLoc getStartLoc() const;
|
||||
|
||||
// Try the pre-header first.
|
||||
if ((HeadBB = getLoopPreheader()) != nullptr)
|
||||
if (DebugLoc DL = HeadBB->getTerminator()->getDebugLoc())
|
||||
return DL;
|
||||
|
||||
// If we have no pre-header or there are no instructions with debug
|
||||
// info in it, try the header.
|
||||
HeadBB = getHeader();
|
||||
if (HeadBB)
|
||||
return HeadBB->getTerminator()->getDebugLoc();
|
||||
|
||||
return DebugLoc();
|
||||
StringRef getName() const {
|
||||
if (BasicBlock *Header = getHeader())
|
||||
if (Header->hasName())
|
||||
return Header->getName();
|
||||
return "<unnamed loop>";
|
||||
}
|
||||
|
||||
private:
|
||||
@ -775,30 +772,23 @@ template <> struct GraphTraits<Loop*> {
|
||||
};
|
||||
|
||||
/// \brief Analysis pass that exposes the \c LoopInfo for a function.
|
||||
class LoopAnalysis {
|
||||
class LoopAnalysis : public AnalysisInfoMixin<LoopAnalysis> {
|
||||
friend AnalysisInfoMixin<LoopAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef LoopInfo Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Provide a name for the analysis for debugging and logging.
|
||||
static StringRef name() { return "LoopAnalysis"; }
|
||||
|
||||
LoopInfo run(Function &F, AnalysisManager<Function> *AM);
|
||||
LoopInfo run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c LoopAnalysis results.
|
||||
class LoopPrinterPass {
|
||||
class LoopPrinterPass : public PassInfoMixin<LoopPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit LoopPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
static StringRef name() { return "LoopPrinterPass"; }
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief The legacy pass manager's analysis pass to compute loop information.
|
||||
@ -828,7 +818,7 @@ public:
|
||||
};
|
||||
|
||||
/// \brief Pass for printing a loop's contents as LLVM's text IR assembly.
|
||||
class PrintLoopPass {
|
||||
class PrintLoopPass : public PassInfoMixin<PrintLoopPass> {
|
||||
raw_ostream &OS;
|
||||
std::string Banner;
|
||||
|
||||
@ -836,8 +826,7 @@ public:
|
||||
PrintLoopPass();
|
||||
PrintLoopPass(raw_ostream &OS, const std::string &Banner = "");
|
||||
|
||||
PreservedAnalyses run(Loop &L);
|
||||
static StringRef name() { return "PrintLoopPass"; }
|
||||
PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -277,7 +277,7 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
|
||||
}
|
||||
assert(HasInsideLoopPreds && "Loop block has no in-loop predecessors!");
|
||||
assert(HasInsideLoopSuccs && "Loop block has no in-loop successors!");
|
||||
assert(BB != getHeader()->getParent()->begin() &&
|
||||
assert(BB != &getHeader()->getParent()->front() &&
|
||||
"Loop contains function entry block!");
|
||||
|
||||
NumVisited++;
|
||||
|
@ -88,9 +88,10 @@ public:
|
||||
virtual void deleteAnalysisLoop(Loop *L) {}
|
||||
|
||||
protected:
|
||||
/// skipOptnoneFunction - Containing function has Attribute::OptimizeNone
|
||||
/// and most transformation passes should skip it.
|
||||
bool skipOptnoneFunction(const Loop *L) const;
|
||||
/// Optional passes call this function to check whether the pass should be
|
||||
/// skipped. This is the case when Attribute::OptimizeNone is set or when
|
||||
/// optimization bisect is over the limit.
|
||||
bool skipLoop(const Loop *L) const;
|
||||
};
|
||||
|
||||
class LPPassManager : public FunctionPass, public PMDataManager {
|
||||
|
142
contrib/llvm/include/llvm/Analysis/LoopPassManager.h
Normal file
142
contrib/llvm/include/llvm/Analysis/LoopPassManager.h
Normal file
@ -0,0 +1,142 @@
|
||||
//===- LoopPassManager.h - Loop 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 loops in LLVM IR.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPPASSMANAGER_H
|
||||
#define LLVM_ANALYSIS_LOOPPASSMANAGER_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern template class PassManager<Loop>;
|
||||
/// \brief The loop pass manager.
|
||||
///
|
||||
/// See the documentation for the PassManager template for details. It runs a
|
||||
/// sequency of loop passes over each loop that the manager is run over. This
|
||||
/// typedef serves as a convenient way to refer to this construct.
|
||||
typedef PassManager<Loop> LoopPassManager;
|
||||
|
||||
extern template class AnalysisManager<Loop>;
|
||||
/// \brief The loop analysis manager.
|
||||
///
|
||||
/// See the documentation for the AnalysisManager template for detail
|
||||
/// documentation. This typedef serves as a convenient way to refer to this
|
||||
/// construct in the adaptors and proxies used to integrate this into the larger
|
||||
/// pass manager infrastructure.
|
||||
typedef AnalysisManager<Loop> LoopAnalysisManager;
|
||||
|
||||
extern template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
|
||||
/// A proxy from a \c LoopAnalysisManager to a \c Function.
|
||||
typedef InnerAnalysisManagerProxy<LoopAnalysisManager, Function>
|
||||
LoopAnalysisManagerFunctionProxy;
|
||||
|
||||
extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>;
|
||||
/// A proxy from a \c FunctionAnalysisManager to a \c Loop.
|
||||
typedef OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>
|
||||
FunctionAnalysisManagerLoopProxy;
|
||||
|
||||
/// Returns the minimum set of Analyses that all loop passes must preserve.
|
||||
PreservedAnalyses getLoopPassPreservedAnalyses();
|
||||
|
||||
/// \brief Adaptor that maps from a function to its loops.
|
||||
///
|
||||
/// Designed to allow composition of a LoopPass(Manager) and a
|
||||
/// FunctionPassManager. Note that if this pass is constructed with a \c
|
||||
/// FunctionAnalysisManager it will run the \c LoopAnalysisManagerFunctionProxy
|
||||
/// analysis prior to running the loop passes over the function to enable a \c
|
||||
/// LoopAnalysisManager to be used within this run safely.
|
||||
template <typename LoopPassT>
|
||||
class FunctionToLoopPassAdaptor
|
||||
: public PassInfoMixin<FunctionToLoopPassAdaptor<LoopPassT>> {
|
||||
public:
|
||||
explicit FunctionToLoopPassAdaptor(LoopPassT Pass)
|
||||
: Pass(std::move(Pass)) {}
|
||||
// We have to explicitly define all the special member functions because MSVC
|
||||
// refuses to generate them.
|
||||
FunctionToLoopPassAdaptor(const FunctionToLoopPassAdaptor &Arg)
|
||||
: Pass(Arg.Pass) {}
|
||||
FunctionToLoopPassAdaptor(FunctionToLoopPassAdaptor &&Arg)
|
||||
: Pass(std::move(Arg.Pass)) {}
|
||||
friend void swap(FunctionToLoopPassAdaptor &LHS,
|
||||
FunctionToLoopPassAdaptor &RHS) {
|
||||
using std::swap;
|
||||
swap(LHS.Pass, RHS.Pass);
|
||||
}
|
||||
FunctionToLoopPassAdaptor &operator=(FunctionToLoopPassAdaptor RHS) {
|
||||
swap(*this, RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Runs the loop passes across every loop in the function.
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
|
||||
// Setup the loop analysis manager from its proxy.
|
||||
LoopAnalysisManager &LAM =
|
||||
AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager();
|
||||
// Get the loop structure for this function
|
||||
LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
|
||||
// We want to visit the loops in reverse post-order. We'll build the stack
|
||||
// of loops to visit in Loops by first walking the loops in pre-order.
|
||||
SmallVector<Loop *, 2> Loops;
|
||||
SmallVector<Loop *, 2> WorkList(LI.begin(), LI.end());
|
||||
while (!WorkList.empty()) {
|
||||
Loop *L = WorkList.pop_back_val();
|
||||
WorkList.insert(WorkList.end(), L->begin(), L->end());
|
||||
Loops.push_back(L);
|
||||
}
|
||||
|
||||
// Now pop each element off of the stack to visit the loops in reverse
|
||||
// post-order.
|
||||
for (auto *L : reverse(Loops)) {
|
||||
PreservedAnalyses PassPA = Pass.run(*L, LAM);
|
||||
assert(PassPA.preserved(getLoopPassPreservedAnalyses()) &&
|
||||
"Loop passes must preserve all relevant analyses");
|
||||
|
||||
// We know that the loop pass couldn't have invalidated any other loop's
|
||||
// analyses (that's the contract of a loop pass), so directly handle the
|
||||
// loop analysis manager's invalidation here. Also, update the
|
||||
// preserved analyses to reflect that once invalidated these can again
|
||||
// be preserved.
|
||||
PassPA = LAM.invalidate(*L, std::move(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
|
||||
// loop analyses by the proxy, but that's OK because we've taken care to
|
||||
// invalidate analyses in the loop analysis manager incrementally above.
|
||||
PA.preserve<LoopAnalysisManagerFunctionProxy>();
|
||||
return PA;
|
||||
}
|
||||
|
||||
private:
|
||||
LoopPassT Pass;
|
||||
};
|
||||
|
||||
/// \brief A function to deduce a loop pass type and wrap it in the templated
|
||||
/// adaptor.
|
||||
template <typename LoopPassT>
|
||||
FunctionToLoopPassAdaptor<LoopPassT>
|
||||
createFunctionToLoopPassAdaptor(LoopPassT Pass) {
|
||||
return FunctionToLoopPassAdaptor<LoopPassT>(std::move(Pass));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_ANALYSIS_LOOPPASSMANAGER_H
|
95
contrib/llvm/include/llvm/Analysis/LoopUnrollAnalyzer.h
Normal file
95
contrib/llvm/include/llvm/Analysis/LoopUnrollAnalyzer.h
Normal file
@ -0,0 +1,95 @@
|
||||
//===- llvm/Analysis/LoopUnrollAnalyzer.h - Loop Unroll Analyzer-*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements UnrolledInstAnalyzer class. It's used for predicting
|
||||
// potential effects that loop unrolling might have, such as enabling constant
|
||||
// propagation and other optimizations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPUNROLLANALYZER_H
|
||||
#define LLVM_ANALYSIS_LOOPUNROLLANALYZER_H
|
||||
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
|
||||
// This class is used to get an estimate of the optimization effects that we
|
||||
// could get from complete loop unrolling. It comes from the fact that some
|
||||
// loads might be replaced with concrete constant values and that could trigger
|
||||
// a chain of instruction simplifications.
|
||||
//
|
||||
// E.g. we might have:
|
||||
// int a[] = {0, 1, 0};
|
||||
// v = 0;
|
||||
// for (i = 0; i < 3; i ++)
|
||||
// v += b[i]*a[i];
|
||||
// If we completely unroll the loop, we would get:
|
||||
// v = b[0]*a[0] + b[1]*a[1] + b[2]*a[2]
|
||||
// Which then will be simplified to:
|
||||
// v = b[0]* 0 + b[1]* 1 + b[2]* 0
|
||||
// And finally:
|
||||
// v = b[1]
|
||||
namespace llvm {
|
||||
class UnrolledInstAnalyzer : private InstVisitor<UnrolledInstAnalyzer, bool> {
|
||||
typedef InstVisitor<UnrolledInstAnalyzer, bool> Base;
|
||||
friend class InstVisitor<UnrolledInstAnalyzer, bool>;
|
||||
struct SimplifiedAddress {
|
||||
Value *Base = nullptr;
|
||||
ConstantInt *Offset = nullptr;
|
||||
};
|
||||
|
||||
public:
|
||||
UnrolledInstAnalyzer(unsigned Iteration,
|
||||
DenseMap<Value *, Constant *> &SimplifiedValues,
|
||||
ScalarEvolution &SE, const Loop *L)
|
||||
: SimplifiedValues(SimplifiedValues), SE(SE), L(L) {
|
||||
IterationNumber = SE.getConstant(APInt(64, Iteration));
|
||||
}
|
||||
|
||||
// Allow access to the initial visit method.
|
||||
using Base::visit;
|
||||
|
||||
private:
|
||||
/// \brief A cache of pointer bases and constant-folded offsets corresponding
|
||||
/// to GEP (or derived from GEP) instructions.
|
||||
///
|
||||
/// In order to find the base pointer one needs to perform non-trivial
|
||||
/// traversal of the corresponding SCEV expression, so it's good to have the
|
||||
/// results saved.
|
||||
DenseMap<Value *, SimplifiedAddress> SimplifiedAddresses;
|
||||
|
||||
/// \brief SCEV expression corresponding to number of currently simulated
|
||||
/// iteration.
|
||||
const SCEV *IterationNumber;
|
||||
|
||||
/// \brief A Value->Constant map for keeping values that we managed to
|
||||
/// constant-fold on the given iteration.
|
||||
///
|
||||
/// While we walk the loop instructions, we build up and maintain a mapping
|
||||
/// of simplified values specific to this iteration. The idea is to propagate
|
||||
/// any special information we have about loads that can be replaced with
|
||||
/// constants after complete unrolling, and account for likely simplifications
|
||||
/// post-unrolling.
|
||||
DenseMap<Value *, Constant *> &SimplifiedValues;
|
||||
|
||||
ScalarEvolution &SE;
|
||||
const Loop *L;
|
||||
|
||||
bool simplifyInstWithSCEV(Instruction *I);
|
||||
|
||||
bool visitInstruction(Instruction &I) { return simplifyInstWithSCEV(&I); }
|
||||
bool visitBinaryOperator(BinaryOperator &I);
|
||||
bool visitLoad(LoadInst &I);
|
||||
bool visitCastInst(CastInst &I);
|
||||
bool visitCmpInst(CmpInst &I);
|
||||
bool visitPHINode(PHINode &PN);
|
||||
};
|
||||
}
|
||||
#endif
|
@ -32,6 +32,11 @@ class TargetLibraryInfo;
|
||||
class Type;
|
||||
class Value;
|
||||
|
||||
enum class ObjSizeMode {
|
||||
Exact = 0,
|
||||
Min = 1,
|
||||
Max = 2
|
||||
};
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates or reallocates memory (either malloc, calloc, realloc, or strdup
|
||||
@ -130,8 +135,11 @@ static inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
|
||||
/// underlying object pointed to by Ptr.
|
||||
/// If RoundToAlign is true, then Size is rounded up to the aligment of allocas,
|
||||
/// byval arguments, and global variables.
|
||||
/// If Mode is Min or Max the size will be evaluated even if it depends on
|
||||
/// a condition and corresponding value will be returned (min or max).
|
||||
bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI, bool RoundToAlign = false);
|
||||
const TargetLibraryInfo *TLI, bool RoundToAlign = false,
|
||||
ObjSizeMode Mode = ObjSizeMode::Exact);
|
||||
|
||||
typedef std::pair<APInt, APInt> SizeOffsetType;
|
||||
|
||||
@ -143,6 +151,7 @@ class ObjectSizeOffsetVisitor
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
bool RoundToAlign;
|
||||
ObjSizeMode Mode;
|
||||
unsigned IntTyBits;
|
||||
APInt Zero;
|
||||
SmallPtrSet<Instruction *, 8> SeenInsts;
|
||||
@ -155,19 +164,20 @@ class ObjectSizeOffsetVisitor
|
||||
|
||||
public:
|
||||
ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
LLVMContext &Context, bool RoundToAlign = false);
|
||||
LLVMContext &Context, bool RoundToAlign = false,
|
||||
ObjSizeMode Mode = ObjSizeMode::Exact);
|
||||
|
||||
SizeOffsetType compute(Value *V);
|
||||
|
||||
bool knownSize(SizeOffsetType &SizeOffset) {
|
||||
static bool knownSize(const SizeOffsetType &SizeOffset) {
|
||||
return SizeOffset.first.getBitWidth() > 1;
|
||||
}
|
||||
|
||||
bool knownOffset(SizeOffsetType &SizeOffset) {
|
||||
static bool knownOffset(const SizeOffsetType &SizeOffset) {
|
||||
return SizeOffset.second.getBitWidth() > 1;
|
||||
}
|
||||
|
||||
bool bothKnown(SizeOffsetType &SizeOffset) {
|
||||
static bool bothKnown(const SizeOffsetType &SizeOffset) {
|
||||
return knownSize(SizeOffset) && knownOffset(SizeOffset);
|
||||
}
|
||||
|
||||
@ -198,7 +208,7 @@ typedef std::pair<Value*, Value*> SizeOffsetEvalType;
|
||||
class ObjectSizeOffsetEvaluator
|
||||
: public InstVisitor<ObjectSizeOffsetEvaluator, SizeOffsetEvalType> {
|
||||
|
||||
typedef IRBuilder<true, TargetFolder> BuilderTy;
|
||||
typedef IRBuilder<TargetFolder> BuilderTy;
|
||||
typedef std::pair<WeakVH, WeakVH> WeakEvalType;
|
||||
typedef DenseMap<const Value*, WeakEvalType> CacheMapTy;
|
||||
typedef SmallPtrSet<const Value*, 8> PtrSetTy;
|
||||
|
@ -15,452 +15,493 @@
|
||||
#define LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerSumType.h"
|
||||
#include "llvm/ADT/PointerEmbeddedInt.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/PredIteratorCache.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class FunctionPass;
|
||||
class Instruction;
|
||||
class CallSite;
|
||||
class AssumptionCache;
|
||||
class MemoryDependenceAnalysis;
|
||||
class PredIteratorCache;
|
||||
class DominatorTree;
|
||||
class PHITransAddr;
|
||||
class Function;
|
||||
class FunctionPass;
|
||||
class Instruction;
|
||||
class CallSite;
|
||||
class AssumptionCache;
|
||||
class MemoryDependenceResults;
|
||||
class PredIteratorCache;
|
||||
class DominatorTree;
|
||||
class PHITransAddr;
|
||||
|
||||
/// MemDepResult - A memory dependence query can return one of three different
|
||||
/// answers, described below.
|
||||
class MemDepResult {
|
||||
enum DepType {
|
||||
/// Invalid - Clients of MemDep never see this.
|
||||
Invalid = 0,
|
||||
|
||||
/// Clobber - This is a dependence on the specified instruction which
|
||||
/// clobbers the desired value. The pointer member of the MemDepResult
|
||||
/// pair holds the instruction that clobbers the memory. For example,
|
||||
/// this occurs when we see a may-aliased store to the memory location we
|
||||
/// care about.
|
||||
///
|
||||
/// There are several cases that may be interesting here:
|
||||
/// 1. Loads are clobbered by may-alias stores.
|
||||
/// 2. Loads are considered clobbered by partially-aliased loads. The
|
||||
/// client may choose to analyze deeper into these cases.
|
||||
Clobber,
|
||||
|
||||
/// Def - This is a dependence on the specified instruction which
|
||||
/// defines/produces the desired memory location. The pointer member of
|
||||
/// the MemDepResult pair holds the instruction that defines the memory.
|
||||
/// Cases of interest:
|
||||
/// 1. This could be a load or store for dependence queries on
|
||||
/// load/store. The value loaded or stored is the produced value.
|
||||
/// Note that the pointer operand may be different than that of the
|
||||
/// queried pointer due to must aliases and phi translation. Note
|
||||
/// that the def may not be the same type as the query, the pointers
|
||||
/// may just be must aliases.
|
||||
/// 2. For loads and stores, this could be an allocation instruction. In
|
||||
/// this case, the load is loading an undef value or a store is the
|
||||
/// first store to (that part of) the allocation.
|
||||
/// 3. Dependence queries on calls return Def only when they are
|
||||
/// readonly calls or memory use intrinsics with identical callees
|
||||
/// and no intervening clobbers. No validation is done that the
|
||||
/// operands to the calls are the same.
|
||||
Def,
|
||||
|
||||
/// Other - This marker indicates that the query has no known dependency
|
||||
/// in the specified block. More detailed state info is encoded in the
|
||||
/// upper part of the pair (i.e. the Instruction*)
|
||||
Other
|
||||
};
|
||||
/// If DepType is "Other", the upper part of the pair
|
||||
/// (i.e. the Instruction* part) is instead used to encode more detailed
|
||||
/// type information as follows
|
||||
enum OtherType {
|
||||
/// NonLocal - This marker indicates that the query has no dependency in
|
||||
/// the specified block. To find out more, the client should query other
|
||||
/// predecessor blocks.
|
||||
NonLocal = 0x4,
|
||||
/// NonFuncLocal - This marker indicates that the query has no
|
||||
/// dependency in the specified function.
|
||||
NonFuncLocal = 0x8,
|
||||
/// Unknown - This marker indicates that the query dependency
|
||||
/// is unknown.
|
||||
Unknown = 0xc
|
||||
};
|
||||
|
||||
typedef PointerIntPair<Instruction*, 2, DepType> PairTy;
|
||||
PairTy Value;
|
||||
explicit MemDepResult(PairTy V) : Value(V) {}
|
||||
|
||||
public:
|
||||
MemDepResult() : Value(nullptr, Invalid) {}
|
||||
|
||||
/// get methods: These are static ctor methods for creating various
|
||||
/// MemDepResult kinds.
|
||||
static MemDepResult getDef(Instruction *Inst) {
|
||||
assert(Inst && "Def requires inst");
|
||||
return MemDepResult(PairTy(Inst, Def));
|
||||
}
|
||||
static MemDepResult getClobber(Instruction *Inst) {
|
||||
assert(Inst && "Clobber requires inst");
|
||||
return MemDepResult(PairTy(Inst, Clobber));
|
||||
}
|
||||
static MemDepResult getNonLocal() {
|
||||
return MemDepResult(
|
||||
PairTy(reinterpret_cast<Instruction*>(NonLocal), Other));
|
||||
}
|
||||
static MemDepResult getNonFuncLocal() {
|
||||
return MemDepResult(
|
||||
PairTy(reinterpret_cast<Instruction*>(NonFuncLocal), Other));
|
||||
}
|
||||
static MemDepResult getUnknown() {
|
||||
return MemDepResult(
|
||||
PairTy(reinterpret_cast<Instruction*>(Unknown), Other));
|
||||
}
|
||||
|
||||
/// isClobber - Return true if this MemDepResult represents a query that is
|
||||
/// an instruction clobber dependency.
|
||||
bool isClobber() const { return Value.getInt() == Clobber; }
|
||||
|
||||
/// isDef - Return true if this MemDepResult represents a query that is
|
||||
/// an instruction definition dependency.
|
||||
bool isDef() const { return Value.getInt() == Def; }
|
||||
|
||||
/// isNonLocal - Return true if this MemDepResult represents a query that
|
||||
/// is transparent to the start of the block, but where a non-local hasn't
|
||||
/// been done.
|
||||
bool isNonLocal() const {
|
||||
return Value.getInt() == Other
|
||||
&& Value.getPointer() == reinterpret_cast<Instruction*>(NonLocal);
|
||||
}
|
||||
|
||||
/// isNonFuncLocal - Return true if this MemDepResult represents a query
|
||||
/// that is transparent to the start of the function.
|
||||
bool isNonFuncLocal() const {
|
||||
return Value.getInt() == Other
|
||||
&& Value.getPointer() == reinterpret_cast<Instruction*>(NonFuncLocal);
|
||||
}
|
||||
|
||||
/// isUnknown - Return true if this MemDepResult represents a query which
|
||||
/// cannot and/or will not be computed.
|
||||
bool isUnknown() const {
|
||||
return Value.getInt() == Other
|
||||
&& Value.getPointer() == reinterpret_cast<Instruction*>(Unknown);
|
||||
}
|
||||
|
||||
/// getInst() - If this is a normal dependency, return the instruction that
|
||||
/// is depended on. Otherwise, return null.
|
||||
Instruction *getInst() const {
|
||||
if (Value.getInt() == Other) return nullptr;
|
||||
return Value.getPointer();
|
||||
}
|
||||
|
||||
bool operator==(const MemDepResult &M) const { return Value == M.Value; }
|
||||
bool operator!=(const MemDepResult &M) const { return Value != M.Value; }
|
||||
bool operator<(const MemDepResult &M) const { return Value < M.Value; }
|
||||
bool operator>(const MemDepResult &M) const { return Value > M.Value; }
|
||||
|
||||
private:
|
||||
friend class MemoryDependenceAnalysis;
|
||||
/// Dirty - Entries with this marker occur in a LocalDeps map or
|
||||
/// NonLocalDeps map when the instruction they previously referenced was
|
||||
/// removed from MemDep. In either case, the entry may include an
|
||||
/// instruction pointer. If so, the pointer is an instruction in the
|
||||
/// block where scanning can start from, saving some work.
|
||||
/// A memory dependence query can return one of three different answers.
|
||||
class MemDepResult {
|
||||
enum DepType {
|
||||
/// Clients of MemDep never see this.
|
||||
///
|
||||
/// In a default-constructed MemDepResult object, the type will be Dirty
|
||||
/// Entries with this marker occur in a LocalDeps map or NonLocalDeps map
|
||||
/// when the instruction they previously referenced was removed from
|
||||
/// MemDep. In either case, the entry may include an instruction pointer.
|
||||
/// If so, the pointer is an instruction in the block where scanning can
|
||||
/// start from, saving some work.
|
||||
///
|
||||
/// In a default-constructed MemDepResult object, the type will be Invalid
|
||||
/// and the instruction pointer will be null.
|
||||
Invalid = 0,
|
||||
|
||||
/// This is a dependence on the specified instruction which clobbers the
|
||||
/// desired value. The pointer member of the MemDepResult pair holds the
|
||||
/// instruction that clobbers the memory. For example, this occurs when we
|
||||
/// see a may-aliased store to the memory location we care about.
|
||||
///
|
||||
/// There are several cases that may be interesting here:
|
||||
/// 1. Loads are clobbered by may-alias stores.
|
||||
/// 2. Loads are considered clobbered by partially-aliased loads. The
|
||||
/// client may choose to analyze deeper into these cases.
|
||||
Clobber,
|
||||
|
||||
/// isDirty - Return true if this is a MemDepResult in its dirty/invalid.
|
||||
/// state.
|
||||
bool isDirty() const { return Value.getInt() == Invalid; }
|
||||
/// This is a dependence on the specified instruction which defines or
|
||||
/// produces the desired memory location. The pointer member of the
|
||||
/// MemDepResult pair holds the instruction that defines the memory.
|
||||
///
|
||||
/// Cases of interest:
|
||||
/// 1. This could be a load or store for dependence queries on
|
||||
/// load/store. The value loaded or stored is the produced value.
|
||||
/// Note that the pointer operand may be different than that of the
|
||||
/// queried pointer due to must aliases and phi translation. Note
|
||||
/// that the def may not be the same type as the query, the pointers
|
||||
/// may just be must aliases.
|
||||
/// 2. For loads and stores, this could be an allocation instruction. In
|
||||
/// this case, the load is loading an undef value or a store is the
|
||||
/// first store to (that part of) the allocation.
|
||||
/// 3. Dependence queries on calls return Def only when they are readonly
|
||||
/// calls or memory use intrinsics with identical callees and no
|
||||
/// intervening clobbers. No validation is done that the operands to
|
||||
/// the calls are the same.
|
||||
Def,
|
||||
|
||||
static MemDepResult getDirty(Instruction *Inst) {
|
||||
return MemDepResult(PairTy(Inst, Invalid));
|
||||
}
|
||||
/// This marker indicates that the query has no known dependency in the
|
||||
/// specified block.
|
||||
///
|
||||
/// More detailed state info is encoded in the upper part of the pair (i.e.
|
||||
/// the Instruction*)
|
||||
Other
|
||||
};
|
||||
|
||||
/// NonLocalDepEntry - This is an entry in the NonLocalDepInfo cache. For
|
||||
/// each BasicBlock (the BB entry) it keeps a MemDepResult.
|
||||
class NonLocalDepEntry {
|
||||
BasicBlock *BB;
|
||||
MemDepResult Result;
|
||||
/// If DepType is "Other", the upper part of the sum type is an encoding of
|
||||
/// the following more detailed type information.
|
||||
enum OtherType {
|
||||
/// This marker indicates that the query has no dependency in the specified
|
||||
/// block.
|
||||
///
|
||||
/// To find out more, the client should query other predecessor blocks.
|
||||
NonLocal = 1,
|
||||
/// This marker indicates that the query has no dependency in the specified
|
||||
/// function.
|
||||
NonFuncLocal,
|
||||
/// This marker indicates that the query dependency is unknown.
|
||||
Unknown
|
||||
};
|
||||
|
||||
public:
|
||||
NonLocalDepEntry(BasicBlock *bb, MemDepResult result)
|
||||
typedef PointerSumType<
|
||||
DepType, PointerSumTypeMember<Invalid, Instruction *>,
|
||||
PointerSumTypeMember<Clobber, Instruction *>,
|
||||
PointerSumTypeMember<Def, Instruction *>,
|
||||
PointerSumTypeMember<Other, PointerEmbeddedInt<OtherType, 3>>>
|
||||
ValueTy;
|
||||
ValueTy Value;
|
||||
explicit MemDepResult(ValueTy V) : Value(V) {}
|
||||
|
||||
public:
|
||||
MemDepResult() : Value() {}
|
||||
|
||||
/// get methods: These are static ctor methods for creating various
|
||||
/// MemDepResult kinds.
|
||||
static MemDepResult getDef(Instruction *Inst) {
|
||||
assert(Inst && "Def requires inst");
|
||||
return MemDepResult(ValueTy::create<Def>(Inst));
|
||||
}
|
||||
static MemDepResult getClobber(Instruction *Inst) {
|
||||
assert(Inst && "Clobber requires inst");
|
||||
return MemDepResult(ValueTy::create<Clobber>(Inst));
|
||||
}
|
||||
static MemDepResult getNonLocal() {
|
||||
return MemDepResult(ValueTy::create<Other>(NonLocal));
|
||||
}
|
||||
static MemDepResult getNonFuncLocal() {
|
||||
return MemDepResult(ValueTy::create<Other>(NonFuncLocal));
|
||||
}
|
||||
static MemDepResult getUnknown() {
|
||||
return MemDepResult(ValueTy::create<Other>(Unknown));
|
||||
}
|
||||
|
||||
/// Tests if this MemDepResult represents a query that is an instruction
|
||||
/// clobber dependency.
|
||||
bool isClobber() const { return Value.is<Clobber>(); }
|
||||
|
||||
/// Tests if this MemDepResult represents a query that is an instruction
|
||||
/// definition dependency.
|
||||
bool isDef() const { return Value.is<Def>(); }
|
||||
|
||||
/// Tests if this MemDepResult represents a query that is transparent to the
|
||||
/// start of the block, but where a non-local hasn't been done.
|
||||
bool isNonLocal() const {
|
||||
return Value.is<Other>() && Value.cast<Other>() == NonLocal;
|
||||
}
|
||||
|
||||
/// Tests if this MemDepResult represents a query that is transparent to the
|
||||
/// start of the function.
|
||||
bool isNonFuncLocal() const {
|
||||
return Value.is<Other>() && Value.cast<Other>() == NonFuncLocal;
|
||||
}
|
||||
|
||||
/// Tests if this MemDepResult represents a query which cannot and/or will
|
||||
/// not be computed.
|
||||
bool isUnknown() const {
|
||||
return Value.is<Other>() && Value.cast<Other>() == Unknown;
|
||||
}
|
||||
|
||||
/// If this is a normal dependency, returns the instruction that is depended
|
||||
/// on. Otherwise, returns null.
|
||||
Instruction *getInst() const {
|
||||
switch (Value.getTag()) {
|
||||
case Invalid:
|
||||
return Value.cast<Invalid>();
|
||||
case Clobber:
|
||||
return Value.cast<Clobber>();
|
||||
case Def:
|
||||
return Value.cast<Def>();
|
||||
case Other:
|
||||
return nullptr;
|
||||
}
|
||||
llvm_unreachable("Unknown discriminant!");
|
||||
}
|
||||
|
||||
bool operator==(const MemDepResult &M) const { return Value == M.Value; }
|
||||
bool operator!=(const MemDepResult &M) const { return Value != M.Value; }
|
||||
bool operator<(const MemDepResult &M) const { return Value < M.Value; }
|
||||
bool operator>(const MemDepResult &M) const { return Value > M.Value; }
|
||||
|
||||
private:
|
||||
friend class MemoryDependenceResults;
|
||||
|
||||
/// Tests if this is a MemDepResult in its dirty/invalid. state.
|
||||
bool isDirty() const { return Value.is<Invalid>(); }
|
||||
|
||||
static MemDepResult getDirty(Instruction *Inst) {
|
||||
return MemDepResult(ValueTy::create<Invalid>(Inst));
|
||||
}
|
||||
};
|
||||
|
||||
/// This is an entry in the NonLocalDepInfo cache.
|
||||
///
|
||||
/// For each BasicBlock (the BB entry) it keeps a MemDepResult.
|
||||
class NonLocalDepEntry {
|
||||
BasicBlock *BB;
|
||||
MemDepResult Result;
|
||||
|
||||
public:
|
||||
NonLocalDepEntry(BasicBlock *bb, MemDepResult result)
|
||||
: BB(bb), Result(result) {}
|
||||
|
||||
// This is used for searches.
|
||||
NonLocalDepEntry(BasicBlock *bb) : BB(bb) {}
|
||||
// This is used for searches.
|
||||
NonLocalDepEntry(BasicBlock *bb) : BB(bb) {}
|
||||
|
||||
// BB is the sort key, it can't be changed.
|
||||
BasicBlock *getBB() const { return BB; }
|
||||
// BB is the sort key, it can't be changed.
|
||||
BasicBlock *getBB() const { return BB; }
|
||||
|
||||
void setResult(const MemDepResult &R) { Result = R; }
|
||||
void setResult(const MemDepResult &R) { Result = R; }
|
||||
|
||||
const MemDepResult &getResult() const { return Result; }
|
||||
const MemDepResult &getResult() const { return Result; }
|
||||
|
||||
bool operator<(const NonLocalDepEntry &RHS) const {
|
||||
return BB < RHS.BB;
|
||||
}
|
||||
};
|
||||
bool operator<(const NonLocalDepEntry &RHS) const { return BB < RHS.BB; }
|
||||
};
|
||||
|
||||
/// NonLocalDepResult - This is a result from a NonLocal dependence query.
|
||||
/// For each BasicBlock (the BB entry) it keeps a MemDepResult and the
|
||||
/// (potentially phi translated) address that was live in the block.
|
||||
class NonLocalDepResult {
|
||||
NonLocalDepEntry Entry;
|
||||
Value *Address;
|
||||
/// This is a result from a NonLocal dependence query.
|
||||
///
|
||||
/// For each BasicBlock (the BB entry) it keeps a MemDepResult and the
|
||||
/// (potentially phi translated) address that was live in the block.
|
||||
class NonLocalDepResult {
|
||||
NonLocalDepEntry Entry;
|
||||
Value *Address;
|
||||
|
||||
public:
|
||||
NonLocalDepResult(BasicBlock *bb, MemDepResult result, Value *address)
|
||||
public:
|
||||
NonLocalDepResult(BasicBlock *bb, MemDepResult result, Value *address)
|
||||
: Entry(bb, result), Address(address) {}
|
||||
|
||||
// BB is the sort key, it can't be changed.
|
||||
BasicBlock *getBB() const { return Entry.getBB(); }
|
||||
// BB is the sort key, it can't be changed.
|
||||
BasicBlock *getBB() const { return Entry.getBB(); }
|
||||
|
||||
void setResult(const MemDepResult &R, Value *Addr) {
|
||||
Entry.setResult(R);
|
||||
Address = Addr;
|
||||
}
|
||||
void setResult(const MemDepResult &R, Value *Addr) {
|
||||
Entry.setResult(R);
|
||||
Address = Addr;
|
||||
}
|
||||
|
||||
const MemDepResult &getResult() const { return Entry.getResult(); }
|
||||
const MemDepResult &getResult() const { return Entry.getResult(); }
|
||||
|
||||
/// getAddress - Return the address of this pointer in this block. This can
|
||||
/// be different than the address queried for the non-local result because
|
||||
/// of phi translation. This returns null if the address was not available
|
||||
/// in a block (i.e. because phi translation failed) or if this is a cached
|
||||
/// result and that address was deleted.
|
||||
/// Returns the address of this pointer in this block.
|
||||
///
|
||||
/// This can be different than the address queried for the non-local result
|
||||
/// because of phi translation. This returns null if the address was not
|
||||
/// available in a block (i.e. because phi translation failed) or if this is
|
||||
/// a cached result and that address was deleted.
|
||||
///
|
||||
/// The address is always null for a non-local 'call' dependence.
|
||||
Value *getAddress() const { return Address; }
|
||||
};
|
||||
|
||||
/// Provides a lazy, caching interface for making common memory aliasing
|
||||
/// information queries, backed by LLVM's alias analysis passes.
|
||||
///
|
||||
/// The dependency information returned is somewhat unusual, but is pragmatic.
|
||||
/// If queried about a store or call that might modify memory, the analysis
|
||||
/// will return the instruction[s] that may either load from that memory or
|
||||
/// store to it. If queried with a load or call that can never modify memory,
|
||||
/// the analysis will return calls and stores that might modify the pointer,
|
||||
/// but generally does not return loads unless a) they are volatile, or
|
||||
/// b) they load from *must-aliased* pointers. Returning a dependence on
|
||||
/// must-alias'd pointers instead of all pointers interacts well with the
|
||||
/// internal caching mechanism.
|
||||
class MemoryDependenceResults {
|
||||
// A map from instructions to their dependency.
|
||||
typedef DenseMap<Instruction *, MemDepResult> LocalDepMapType;
|
||||
LocalDepMapType LocalDeps;
|
||||
|
||||
public:
|
||||
typedef std::vector<NonLocalDepEntry> NonLocalDepInfo;
|
||||
|
||||
private:
|
||||
/// A pair<Value*, bool> where the bool is true if the dependence is a read
|
||||
/// only dependence, false if read/write.
|
||||
typedef PointerIntPair<const Value *, 1, bool> ValueIsLoadPair;
|
||||
|
||||
/// This pair is used when caching information for a block.
|
||||
///
|
||||
/// If the pointer is null, the cache value is not a full query that starts
|
||||
/// at the specified block. If non-null, the bool indicates whether or not
|
||||
/// the contents of the block was skipped.
|
||||
typedef PointerIntPair<BasicBlock *, 1, bool> BBSkipFirstBlockPair;
|
||||
|
||||
/// This record is the information kept for each (value, is load) pair.
|
||||
struct NonLocalPointerInfo {
|
||||
/// The pair of the block and the skip-first-block flag.
|
||||
BBSkipFirstBlockPair Pair;
|
||||
/// The results of the query for each relevant block.
|
||||
NonLocalDepInfo NonLocalDeps;
|
||||
/// The maximum size of the dereferences of the pointer.
|
||||
///
|
||||
/// The address is always null for a non-local 'call' dependence.
|
||||
Value *getAddress() const { return Address; }
|
||||
/// May be UnknownSize if the sizes are unknown.
|
||||
uint64_t Size;
|
||||
/// The AA tags associated with dereferences of the pointer.
|
||||
///
|
||||
/// The members may be null if there are no tags or conflicting tags.
|
||||
AAMDNodes AATags;
|
||||
|
||||
NonLocalPointerInfo() : Size(MemoryLocation::UnknownSize) {}
|
||||
};
|
||||
|
||||
/// MemoryDependenceAnalysis - This is an analysis that determines, for a
|
||||
/// given memory operation, what preceding memory operations it depends on.
|
||||
/// It builds on alias analysis information, and tries to provide a lazy,
|
||||
/// caching interface to a common kind of alias information query.
|
||||
/// This map stores the cached results of doing a pointer lookup at the
|
||||
/// bottom of a block.
|
||||
///
|
||||
/// The dependency information returned is somewhat unusual, but is pragmatic.
|
||||
/// If queried about a store or call that might modify memory, the analysis
|
||||
/// will return the instruction[s] that may either load from that memory or
|
||||
/// store to it. If queried with a load or call that can never modify memory,
|
||||
/// the analysis will return calls and stores that might modify the pointer,
|
||||
/// but generally does not return loads unless a) they are volatile, or
|
||||
/// b) they load from *must-aliased* pointers. Returning a dependence on
|
||||
/// must-alias'd pointers instead of all pointers interacts well with the
|
||||
/// internal caching mechanism.
|
||||
/// The key of this map is the pointer+isload bit, the value is a list of
|
||||
/// <bb->result> mappings.
|
||||
typedef DenseMap<ValueIsLoadPair, NonLocalPointerInfo>
|
||||
CachedNonLocalPointerInfo;
|
||||
CachedNonLocalPointerInfo NonLocalPointerDeps;
|
||||
|
||||
// A map from instructions to their non-local pointer dependencies.
|
||||
typedef DenseMap<Instruction *, SmallPtrSet<ValueIsLoadPair, 4>>
|
||||
ReverseNonLocalPtrDepTy;
|
||||
ReverseNonLocalPtrDepTy ReverseNonLocalPtrDeps;
|
||||
|
||||
/// This is the instruction we keep for each cached access that we have for
|
||||
/// an instruction.
|
||||
///
|
||||
class MemoryDependenceAnalysis : public FunctionPass {
|
||||
// A map from instructions to their dependency.
|
||||
typedef DenseMap<Instruction*, MemDepResult> LocalDepMapType;
|
||||
LocalDepMapType LocalDeps;
|
||||
/// The pointer is an owning pointer and the bool indicates whether we have
|
||||
/// any dirty bits in the set.
|
||||
typedef std::pair<NonLocalDepInfo, bool> PerInstNLInfo;
|
||||
|
||||
public:
|
||||
typedef std::vector<NonLocalDepEntry> NonLocalDepInfo;
|
||||
// A map from instructions to their non-local dependencies.
|
||||
typedef DenseMap<Instruction *, PerInstNLInfo> NonLocalDepMapType;
|
||||
|
||||
private:
|
||||
/// ValueIsLoadPair - This is a pair<Value*, bool> where the bool is true if
|
||||
/// the dependence is a read only dependence, false if read/write.
|
||||
typedef PointerIntPair<const Value*, 1, bool> ValueIsLoadPair;
|
||||
NonLocalDepMapType NonLocalDeps;
|
||||
|
||||
/// BBSkipFirstBlockPair - This pair is used when caching information for a
|
||||
/// block. If the pointer is null, the cache value is not a full query that
|
||||
/// starts at the specified block. If non-null, the bool indicates whether
|
||||
/// or not the contents of the block was skipped.
|
||||
typedef PointerIntPair<BasicBlock*, 1, bool> BBSkipFirstBlockPair;
|
||||
// A reverse mapping from dependencies to the dependees. This is
|
||||
// used when removing instructions to keep the cache coherent.
|
||||
typedef DenseMap<Instruction *, SmallPtrSet<Instruction *, 4>>
|
||||
ReverseDepMapType;
|
||||
ReverseDepMapType ReverseLocalDeps;
|
||||
|
||||
/// NonLocalPointerInfo - This record is the information kept for each
|
||||
/// (value, is load) pair.
|
||||
struct NonLocalPointerInfo {
|
||||
/// Pair - The pair of the block and the skip-first-block flag.
|
||||
BBSkipFirstBlockPair Pair;
|
||||
/// NonLocalDeps - The results of the query for each relevant block.
|
||||
NonLocalDepInfo NonLocalDeps;
|
||||
/// Size - The maximum size of the dereferences of the
|
||||
/// pointer. May be UnknownSize if the sizes are unknown.
|
||||
uint64_t Size;
|
||||
/// AATags - The AA tags associated with dereferences of the
|
||||
/// pointer. The members may be null if there are no tags or
|
||||
/// conflicting tags.
|
||||
AAMDNodes AATags;
|
||||
// A reverse mapping from dependencies to the non-local dependees.
|
||||
ReverseDepMapType ReverseNonLocalDeps;
|
||||
|
||||
NonLocalPointerInfo() : Size(MemoryLocation::UnknownSize) {}
|
||||
};
|
||||
/// Current AA implementation, just a cache.
|
||||
AliasAnalysis &AA;
|
||||
AssumptionCache &AC;
|
||||
const TargetLibraryInfo &TLI;
|
||||
DominatorTree &DT;
|
||||
PredIteratorCache PredCache;
|
||||
|
||||
/// CachedNonLocalPointerInfo - This map stores the cached results of doing
|
||||
/// a pointer lookup at the bottom of a block. The key of this map is the
|
||||
/// pointer+isload bit, the value is a list of <bb->result> mappings.
|
||||
typedef DenseMap<ValueIsLoadPair,
|
||||
NonLocalPointerInfo> CachedNonLocalPointerInfo;
|
||||
CachedNonLocalPointerInfo NonLocalPointerDeps;
|
||||
public:
|
||||
MemoryDependenceResults(AliasAnalysis &AA, AssumptionCache &AC,
|
||||
const TargetLibraryInfo &TLI,
|
||||
DominatorTree &DT)
|
||||
: AA(AA), AC(AC), TLI(TLI), DT(DT) {}
|
||||
|
||||
// A map from instructions to their non-local pointer dependencies.
|
||||
typedef DenseMap<Instruction*,
|
||||
SmallPtrSet<ValueIsLoadPair, 4> > ReverseNonLocalPtrDepTy;
|
||||
ReverseNonLocalPtrDepTy ReverseNonLocalPtrDeps;
|
||||
/// Returns the instruction on which a memory operation depends.
|
||||
///
|
||||
/// See the class comment for more details. It is illegal to call this on
|
||||
/// non-memory instructions.
|
||||
MemDepResult getDependency(Instruction *QueryInst);
|
||||
|
||||
/// PerInstNLInfo - This is the instruction we keep for each cached access
|
||||
/// that we have for an instruction. The pointer is an owning pointer and
|
||||
/// the bool indicates whether we have any dirty bits in the set.
|
||||
typedef std::pair<NonLocalDepInfo, bool> PerInstNLInfo;
|
||||
/// Perform a full dependency query for the specified call, returning the set
|
||||
/// of blocks that the value is potentially live across.
|
||||
///
|
||||
/// The returned set of results will include a "NonLocal" result for all
|
||||
/// blocks where the value is live across.
|
||||
///
|
||||
/// This method assumes the instruction returns a "NonLocal" dependency
|
||||
/// within its own block.
|
||||
///
|
||||
/// This returns a reference to an internal data structure that may be
|
||||
/// invalidated on the next non-local query or when an instruction is
|
||||
/// removed. Clients must copy this data if they want it around longer than
|
||||
/// that.
|
||||
const NonLocalDepInfo &getNonLocalCallDependency(CallSite QueryCS);
|
||||
|
||||
// A map from instructions to their non-local dependencies.
|
||||
typedef DenseMap<Instruction*, PerInstNLInfo> NonLocalDepMapType;
|
||||
|
||||
NonLocalDepMapType NonLocalDeps;
|
||||
|
||||
// A reverse mapping from dependencies to the dependees. This is
|
||||
// used when removing instructions to keep the cache coherent.
|
||||
typedef DenseMap<Instruction*,
|
||||
SmallPtrSet<Instruction*, 4> > ReverseDepMapType;
|
||||
ReverseDepMapType ReverseLocalDeps;
|
||||
|
||||
// A reverse mapping from dependencies to the non-local dependees.
|
||||
ReverseDepMapType ReverseNonLocalDeps;
|
||||
|
||||
/// Current AA implementation, just a cache.
|
||||
AliasAnalysis *AA;
|
||||
DominatorTree *DT;
|
||||
AssumptionCache *AC;
|
||||
const TargetLibraryInfo *TLI;
|
||||
PredIteratorCache PredCache;
|
||||
|
||||
public:
|
||||
MemoryDependenceAnalysis();
|
||||
~MemoryDependenceAnalysis() override;
|
||||
static char ID;
|
||||
|
||||
/// Pass Implementation stuff. This doesn't do any analysis eagerly.
|
||||
bool runOnFunction(Function &) override;
|
||||
|
||||
/// Clean up memory in between runs
|
||||
void releaseMemory() override;
|
||||
|
||||
/// getAnalysisUsage - Does not modify anything. It uses Value Numbering
|
||||
/// and Alias Analysis.
|
||||
///
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// getDependency - Return the instruction on which a memory operation
|
||||
/// depends. See the class comment for more details. It is illegal to call
|
||||
/// this on non-memory instructions.
|
||||
MemDepResult getDependency(Instruction *QueryInst);
|
||||
|
||||
/// getNonLocalCallDependency - Perform a full dependency query for the
|
||||
/// specified call, returning the set of blocks that the value is
|
||||
/// potentially live across. The returned set of results will include a
|
||||
/// "NonLocal" result for all blocks where the value is live across.
|
||||
///
|
||||
/// This method assumes the instruction returns a "NonLocal" dependency
|
||||
/// within its own block.
|
||||
///
|
||||
/// This returns a reference to an internal data structure that may be
|
||||
/// invalidated on the next non-local query or when an instruction is
|
||||
/// removed. Clients must copy this data if they want it around longer than
|
||||
/// that.
|
||||
const NonLocalDepInfo &getNonLocalCallDependency(CallSite QueryCS);
|
||||
|
||||
/// getNonLocalPointerDependency - Perform a full dependency query for an
|
||||
/// access to the QueryInst's specified memory location, returning the set
|
||||
/// of instructions that either define or clobber the value.
|
||||
///
|
||||
/// Warning: For a volatile query instruction, the dependencies will be
|
||||
/// accurate, and thus usable for reordering, but it is never legal to
|
||||
/// remove the query instruction.
|
||||
///
|
||||
/// This method assumes the pointer has a "NonLocal" dependency within
|
||||
/// QueryInst's parent basic block.
|
||||
void getNonLocalPointerDependency(Instruction *QueryInst,
|
||||
/// Perform a full dependency query for an access to the QueryInst's
|
||||
/// specified memory location, returning the set of instructions that either
|
||||
/// define or clobber the value.
|
||||
///
|
||||
/// Warning: For a volatile query instruction, the dependencies will be
|
||||
/// accurate, and thus usable for reordering, but it is never legal to
|
||||
/// remove the query instruction.
|
||||
///
|
||||
/// This method assumes the pointer has a "NonLocal" dependency within
|
||||
/// QueryInst's parent basic block.
|
||||
void getNonLocalPointerDependency(Instruction *QueryInst,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result);
|
||||
|
||||
/// removeInstruction - Remove an instruction from the dependence analysis,
|
||||
/// updating the dependence of instructions that previously depended on it.
|
||||
void removeInstruction(Instruction *InstToRemove);
|
||||
/// Removes an instruction from the dependence analysis, updating the
|
||||
/// dependence of instructions that previously depended on it.
|
||||
void removeInstruction(Instruction *InstToRemove);
|
||||
|
||||
/// invalidateCachedPointerInfo - This method is used to invalidate cached
|
||||
/// information about the specified pointer, because it may be too
|
||||
/// conservative in memdep. This is an optional call that can be used when
|
||||
/// the client detects an equivalence between the pointer and some other
|
||||
/// value and replaces the other value with ptr. This can make Ptr available
|
||||
/// in more places that cached info does not necessarily keep.
|
||||
void invalidateCachedPointerInfo(Value *Ptr);
|
||||
/// Invalidates cached information about the specified pointer, because it
|
||||
/// may be too conservative in memdep.
|
||||
///
|
||||
/// This is an optional call that can be used when the client detects an
|
||||
/// equivalence between the pointer and some other value and replaces the
|
||||
/// other value with ptr. This can make Ptr available in more places that
|
||||
/// cached info does not necessarily keep.
|
||||
void invalidateCachedPointerInfo(Value *Ptr);
|
||||
|
||||
/// invalidateCachedPredecessors - Clear the PredIteratorCache info.
|
||||
/// This needs to be done when the CFG changes, e.g., due to splitting
|
||||
/// critical edges.
|
||||
void invalidateCachedPredecessors();
|
||||
/// Clears the PredIteratorCache info.
|
||||
///
|
||||
/// This needs to be done when the CFG changes, e.g., due to splitting
|
||||
/// critical edges.
|
||||
void invalidateCachedPredecessors();
|
||||
|
||||
/// \brief Return the instruction on which a memory location depends.
|
||||
/// If isLoad is true, this routine ignores may-aliases with read-only
|
||||
/// operations. If isLoad is false, this routine ignores may-aliases
|
||||
/// with reads from read-only locations. If possible, pass the query
|
||||
/// instruction as well; this function may take advantage of the metadata
|
||||
/// annotated to the query instruction to refine the result.
|
||||
///
|
||||
/// Note that this is an uncached query, and thus may be inefficient.
|
||||
///
|
||||
MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc,
|
||||
bool isLoad,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB,
|
||||
Instruction *QueryInst = nullptr);
|
||||
/// Returns the instruction on which a memory location depends.
|
||||
///
|
||||
/// If isLoad is true, this routine ignores may-aliases with read-only
|
||||
/// operations. If isLoad is false, this routine ignores may-aliases
|
||||
/// with reads from read-only locations. If possible, pass the query
|
||||
/// instruction as well; this function may take advantage of the metadata
|
||||
/// annotated to the query instruction to refine the result.
|
||||
///
|
||||
/// Note that this is an uncached query, and thus may be inefficient.
|
||||
MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc, bool isLoad,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB,
|
||||
Instruction *QueryInst = nullptr);
|
||||
|
||||
MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc,
|
||||
bool isLoad,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB,
|
||||
Instruction *QueryInst);
|
||||
MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc,
|
||||
bool isLoad,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB,
|
||||
Instruction *QueryInst);
|
||||
|
||||
/// This analysis looks for other loads and stores with invariant.group
|
||||
/// metadata and the same pointer operand. Returns Unknown if it does not
|
||||
/// find anything, and Def if it can be assumed that 2 instructions load or
|
||||
/// store the same value.
|
||||
/// FIXME: This analysis works only on single block because of restrictions
|
||||
/// at the call site.
|
||||
MemDepResult getInvariantGroupPointerDependency(LoadInst *LI,
|
||||
BasicBlock *BB);
|
||||
/// This analysis looks for other loads and stores with invariant.group
|
||||
/// metadata and the same pointer operand. Returns Unknown if it does not
|
||||
/// find anything, and Def if it can be assumed that 2 instructions load or
|
||||
/// store the same value.
|
||||
/// FIXME: This analysis works only on single block because of restrictions
|
||||
/// at the call site.
|
||||
MemDepResult getInvariantGroupPointerDependency(LoadInst *LI, BasicBlock *BB);
|
||||
|
||||
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
|
||||
/// looks at a memory location for a load (specified by MemLocBase, Offs,
|
||||
/// and Size) and compares it against a load. If the specified load could
|
||||
/// be safely widened to a larger integer load that is 1) still efficient,
|
||||
/// 2) safe for the target, and 3) would provide the specified memory
|
||||
/// location value, then this function returns the size in bytes of the
|
||||
/// load width to use. If not, this returns zero.
|
||||
static unsigned getLoadLoadClobberFullWidthSize(const Value *MemLocBase,
|
||||
int64_t MemLocOffs,
|
||||
unsigned MemLocSize,
|
||||
const LoadInst *LI);
|
||||
/// Looks at a memory location for a load (specified by MemLocBase, Offs, and
|
||||
/// Size) and compares it against a load.
|
||||
///
|
||||
/// If the specified load could be safely widened to a larger integer load
|
||||
/// that is 1) still efficient, 2) safe for the target, and 3) would provide
|
||||
/// the specified memory location value, then this function returns the size
|
||||
/// in bytes of the load width to use. If not, this returns zero.
|
||||
static unsigned getLoadLoadClobberFullWidthSize(const Value *MemLocBase,
|
||||
int64_t MemLocOffs,
|
||||
unsigned MemLocSize,
|
||||
const LoadInst *LI);
|
||||
|
||||
private:
|
||||
MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB);
|
||||
bool getNonLocalPointerDepFromBB(Instruction *QueryInst,
|
||||
const PHITransAddr &Pointer,
|
||||
const MemoryLocation &Loc, bool isLoad,
|
||||
BasicBlock *BB,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result,
|
||||
DenseMap<BasicBlock *, Value *> &Visited,
|
||||
bool SkipFirstBlock = false);
|
||||
MemDepResult GetNonLocalInfoForBlock(Instruction *QueryInst,
|
||||
const MemoryLocation &Loc, bool isLoad,
|
||||
BasicBlock *BB, NonLocalDepInfo *Cache,
|
||||
unsigned NumSortedEntries);
|
||||
/// Release memory in caches.
|
||||
void releaseMemory();
|
||||
|
||||
void RemoveCachedNonLocalPointerDependencies(ValueIsLoadPair P);
|
||||
private:
|
||||
MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB);
|
||||
bool getNonLocalPointerDepFromBB(Instruction *QueryInst,
|
||||
const PHITransAddr &Pointer,
|
||||
const MemoryLocation &Loc, bool isLoad,
|
||||
BasicBlock *BB,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result,
|
||||
DenseMap<BasicBlock *, Value *> &Visited,
|
||||
bool SkipFirstBlock = false);
|
||||
MemDepResult GetNonLocalInfoForBlock(Instruction *QueryInst,
|
||||
const MemoryLocation &Loc, bool isLoad,
|
||||
BasicBlock *BB, NonLocalDepInfo *Cache,
|
||||
unsigned NumSortedEntries);
|
||||
|
||||
/// verifyRemoved - Verify that the specified instruction does not occur
|
||||
/// in our internal data structures.
|
||||
void verifyRemoved(Instruction *Inst) const;
|
||||
};
|
||||
void RemoveCachedNonLocalPointerDependencies(ValueIsLoadPair P);
|
||||
|
||||
void verifyRemoved(Instruction *Inst) const;
|
||||
};
|
||||
|
||||
/// An analysis that produces \c MemoryDependenceResults for a function.
|
||||
///
|
||||
/// This is essentially a no-op because the results are computed entirely
|
||||
/// lazily.
|
||||
class MemoryDependenceAnalysis
|
||||
: public AnalysisInfoMixin<MemoryDependenceAnalysis> {
|
||||
friend AnalysisInfoMixin<MemoryDependenceAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef MemoryDependenceResults Result;
|
||||
|
||||
MemoryDependenceResults run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// A wrapper analysis pass for the legacy pass manager that exposes a \c
|
||||
/// MemoryDepnedenceResults instance.
|
||||
class MemoryDependenceWrapperPass : public FunctionPass {
|
||||
Optional<MemoryDependenceResults> MemDep;
|
||||
public:
|
||||
MemoryDependenceWrapperPass();
|
||||
~MemoryDependenceWrapperPass() override;
|
||||
static char ID;
|
||||
|
||||
/// Pass Implementation stuff. This doesn't do any analysis eagerly.
|
||||
bool runOnFunction(Function &) override;
|
||||
|
||||
/// Clean up memory in between runs
|
||||
void releaseMemory() override;
|
||||
|
||||
/// Does not modify anything. It uses Value Numbering and Alias Analysis.
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
MemoryDependenceResults &getMemDep() { return *MemDep; }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#ifndef LLVM_ANALYSIS_MEMORYLOCATION_H
|
||||
#define LLVM_ANALYSIS_MEMORYLOCATION_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
|
||||
|
91
contrib/llvm/include/llvm/Analysis/ModuleSummaryAnalysis.h
Normal file
91
contrib/llvm/include/llvm/Analysis/ModuleSummaryAnalysis.h
Normal file
@ -0,0 +1,91 @@
|
||||
//===- ModuleSummaryAnalysis.h - Module summary index builder ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This is the interface to build a ModuleSummaryIndex for a module.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_MODULESUMMARYANALYSIS_H
|
||||
#define LLVM_ANALYSIS_MODULESUMMARYANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BlockFrequencyInfo;
|
||||
|
||||
/// Class to build a module summary index for the given Module, possibly from
|
||||
/// a Pass.
|
||||
class ModuleSummaryIndexBuilder {
|
||||
/// The index being built
|
||||
std::unique_ptr<ModuleSummaryIndex> Index;
|
||||
/// The module for which we are building an index
|
||||
const Module *M;
|
||||
|
||||
public:
|
||||
/// Default constructor
|
||||
ModuleSummaryIndexBuilder() = default;
|
||||
|
||||
/// Constructor that builds an index for the given Module. An optional
|
||||
/// callback can be supplied to obtain the frequency info for a function.
|
||||
ModuleSummaryIndexBuilder(
|
||||
const Module *M,
|
||||
std::function<BlockFrequencyInfo *(const Function &F)> Ftor = nullptr);
|
||||
|
||||
/// Get a reference to the index owned by builder
|
||||
ModuleSummaryIndex &getIndex() const { return *Index; }
|
||||
|
||||
/// Take ownership of the built index
|
||||
std::unique_ptr<ModuleSummaryIndex> takeIndex() { return std::move(Index); }
|
||||
|
||||
private:
|
||||
/// Compute summary for given function with optional frequency information
|
||||
void computeFunctionSummary(const Function &F,
|
||||
BlockFrequencyInfo *BFI = nullptr);
|
||||
|
||||
/// Compute summary for given variable with optional frequency information
|
||||
void computeVariableSummary(const GlobalVariable &V);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the ModuleSummaryIndex object.
|
||||
class ModuleSummaryIndexWrapperPass : public ModulePass {
|
||||
std::unique_ptr<ModuleSummaryIndexBuilder> IndexBuilder;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
ModuleSummaryIndexWrapperPass();
|
||||
|
||||
/// Get the index built by pass
|
||||
ModuleSummaryIndex &getIndex() { return IndexBuilder->getIndex(); }
|
||||
const ModuleSummaryIndex &getIndex() const {
|
||||
return IndexBuilder->getIndex();
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
bool doFinalization(Module &M) override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createModuleSummaryIndexWrapperPass - This pass builds a ModuleSummaryIndex
|
||||
// object for the module, to be written to bitcode or LLVM assembly.
|
||||
//
|
||||
ModulePass *createModuleSummaryIndexWrapperPass();
|
||||
|
||||
/// Returns true if \p M is eligible for ThinLTO promotion.
|
||||
///
|
||||
/// Currently we check if it has any any InlineASM that uses an internal symbol.
|
||||
bool moduleCanBeRenamedForThinLTO(const Module &M);
|
||||
}
|
||||
|
||||
#endif
|
@ -24,7 +24,6 @@
|
||||
#define LLVM_ANALYSIS_OBJCARCALIASANALYSIS_H
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -42,8 +41,7 @@ class ObjCARCAAResult : public AAResultBase<ObjCARCAAResult> {
|
||||
const DataLayout &DL;
|
||||
|
||||
public:
|
||||
explicit ObjCARCAAResult(const DataLayout &DL, const TargetLibraryInfo &TLI)
|
||||
: AAResultBase(TLI), DL(DL) {}
|
||||
explicit ObjCARCAAResult(const DataLayout &DL) : AAResultBase(), DL(DL) {}
|
||||
ObjCARCAAResult(ObjCARCAAResult &&Arg)
|
||||
: AAResultBase(std::move(Arg)), DL(Arg.DL) {}
|
||||
|
||||
@ -63,20 +61,14 @@ public:
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
class ObjCARCAA {
|
||||
class ObjCARCAA : public AnalysisInfoMixin<ObjCARCAA> {
|
||||
friend AnalysisInfoMixin<ObjCARCAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef ObjCARCAAResult Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
ObjCARCAAResult run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "ObjCARCAA"; }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
ObjCARCAAResult run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the ObjCARCAAResult object.
|
||||
|
@ -54,6 +54,7 @@ inline bool ModuleHasARC(const Module &M) {
|
||||
M.getNamedValue("objc_release") ||
|
||||
M.getNamedValue("objc_autorelease") ||
|
||||
M.getNamedValue("objc_retainAutoreleasedReturnValue") ||
|
||||
M.getNamedValue("objc_unsafeClaimAutoreleasedReturnValue") ||
|
||||
M.getNamedValue("objc_retainBlock") ||
|
||||
M.getNamedValue("objc_autoreleaseReturnValue") ||
|
||||
M.getNamedValue("objc_autoreleasePoolPush") ||
|
||||
|
@ -30,6 +30,7 @@ namespace objcarc {
|
||||
enum class ARCInstKind {
|
||||
Retain, ///< objc_retain
|
||||
RetainRV, ///< objc_retainAutoreleasedReturnValue
|
||||
ClaimRV, ///< objc_unsafeClaimAutoreleasedReturnValue
|
||||
RetainBlock, ///< objc_retainBlock
|
||||
Release, ///< objc_release
|
||||
Autorelease, ///< objc_autorelease
|
||||
|
104
contrib/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h
Normal file
104
contrib/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h
Normal file
@ -0,0 +1,104 @@
|
||||
//===- OptimizationDiagnosticInfo.h - Optimization Diagnostic ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Optimization diagnostic interfaces. It's packaged as an analysis pass so
|
||||
// that by using this service passes become dependent on BFI as well. BFI is
|
||||
// used to compute the "hotness" of the diagnostic message.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H
|
||||
#define LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
class BlockFrequencyInfo;
|
||||
class DebugLoc;
|
||||
class Function;
|
||||
class LLVMContext;
|
||||
class Loop;
|
||||
class Pass;
|
||||
class Twine;
|
||||
class Value;
|
||||
|
||||
class OptimizationRemarkEmitter {
|
||||
public:
|
||||
OptimizationRemarkEmitter(Function *F, BlockFrequencyInfo *BFI)
|
||||
: F(F), BFI(BFI) {}
|
||||
|
||||
OptimizationRemarkEmitter(OptimizationRemarkEmitter &&Arg)
|
||||
: F(Arg.F), BFI(Arg.BFI) {}
|
||||
|
||||
OptimizationRemarkEmitter &operator=(OptimizationRemarkEmitter &&RHS) {
|
||||
F = RHS.F;
|
||||
BFI = RHS.BFI;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Emit an optimization-missed message.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If
|
||||
/// -Rpass-missed= is given and the name matches the regular expression in
|
||||
/// -Rpass, then the remark will be emitted. \p Fn is the function triggering
|
||||
/// the remark, \p DLoc is the debug location where the diagnostic is
|
||||
/// generated. \p V is the IR Value that identifies the code region. \p Msg is
|
||||
/// the message string to use.
|
||||
void emitOptimizationRemarkMissed(const char *PassName, const DebugLoc &DLoc,
|
||||
Value *V, const Twine &Msg);
|
||||
|
||||
/// \brief Same as above but derives the IR Value for the code region and the
|
||||
/// debug location from the Loop parameter \p L.
|
||||
void emitOptimizationRemarkMissed(const char *PassName, Loop *L,
|
||||
const Twine &Msg);
|
||||
|
||||
private:
|
||||
Function *F;
|
||||
|
||||
BlockFrequencyInfo *BFI;
|
||||
|
||||
Optional<uint64_t> computeHotness(Value *V);
|
||||
|
||||
OptimizationRemarkEmitter(const OptimizationRemarkEmitter &) = delete;
|
||||
void operator=(const OptimizationRemarkEmitter &) = delete;
|
||||
};
|
||||
|
||||
class OptimizationRemarkEmitterWrapperPass : public FunctionPass {
|
||||
std::unique_ptr<OptimizationRemarkEmitter> ORE;
|
||||
|
||||
public:
|
||||
OptimizationRemarkEmitterWrapperPass();
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
OptimizationRemarkEmitter &getORE() {
|
||||
assert(ORE && "pass not run yet");
|
||||
return *ORE;
|
||||
}
|
||||
|
||||
static char ID;
|
||||
};
|
||||
|
||||
class OptimizationRemarkEmitterAnalysis
|
||||
: public AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis> {
|
||||
friend AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
/// \brief Provide the result typedef for this analysis pass.
|
||||
typedef OptimizationRemarkEmitter Result;
|
||||
|
||||
/// \brief Run the analysis pass over a function and produce BFI.
|
||||
Result run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
}
|
||||
#endif // LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H
|
@ -23,13 +23,6 @@ namespace llvm {
|
||||
class Pass;
|
||||
class PassInfo;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createAAEvalPass - This pass implements a simple N^2 alias analysis
|
||||
// accuracy evaluator.
|
||||
//
|
||||
FunctionPass *createAAEvalPass();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createObjCARCAAWrapperPass - This pass implements ObjC-ARC-based
|
||||
@ -47,10 +40,10 @@ namespace llvm {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createDependenceAnalysisPass - This creates an instance of the
|
||||
// DependenceAnalysis pass.
|
||||
// createDependenceAnalysisWrapperPass - This creates an instance of the
|
||||
// DependenceAnalysisWrapper pass.
|
||||
//
|
||||
FunctionPass *createDependenceAnalysisPass();
|
||||
FunctionPass *createDependenceAnalysisWrapperPass();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
|
@ -15,22 +15,62 @@
|
||||
#define LLVM_ANALYSIS_POSTDOMINATORS_H
|
||||
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// PostDominatorTree Class - Concrete subclass of DominatorTree that is used to
|
||||
/// compute the post-dominator tree.
|
||||
///
|
||||
struct PostDominatorTree : public FunctionPass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
DominatorTreeBase<BasicBlock>* DT;
|
||||
struct PostDominatorTree : public DominatorTreeBase<BasicBlock> {
|
||||
typedef DominatorTreeBase<BasicBlock> Base;
|
||||
|
||||
PostDominatorTree() : FunctionPass(ID) {
|
||||
initializePostDominatorTreePass(*PassRegistry::getPassRegistry());
|
||||
DT = new DominatorTreeBase<BasicBlock>(true);
|
||||
PostDominatorTree() : DominatorTreeBase<BasicBlock>(true) {}
|
||||
|
||||
PostDominatorTree(PostDominatorTree &&Arg)
|
||||
: Base(std::move(static_cast<Base &>(Arg))) {}
|
||||
|
||||
PostDominatorTree &operator=(PostDominatorTree &&RHS) {
|
||||
Base::operator=(std::move(static_cast<Base &>(RHS)));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Analysis pass which computes a \c PostDominatorTree.
|
||||
class PostDominatorTreeAnalysis
|
||||
: public AnalysisInfoMixin<PostDominatorTreeAnalysis> {
|
||||
friend AnalysisInfoMixin<PostDominatorTreeAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
/// \brief Provide the result typedef for this analysis pass.
|
||||
typedef PostDominatorTree Result;
|
||||
|
||||
/// \brief Run the analysis pass over a function and produce a post dominator
|
||||
/// tree.
|
||||
PostDominatorTree run(Function &F, FunctionAnalysisManager &);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c PostDominatorTree.
|
||||
class PostDominatorTreePrinterPass
|
||||
: public PassInfoMixin<PostDominatorTreePrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit PostDominatorTreePrinterPass(raw_ostream &OS);
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
struct PostDominatorTreeWrapperPass : public FunctionPass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
PostDominatorTree DT;
|
||||
|
||||
PostDominatorTreeWrapperPass() : FunctionPass(ID) {
|
||||
initializePostDominatorTreeWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
~PostDominatorTree() override;
|
||||
PostDominatorTree &getPostDomTree() { return DT; }
|
||||
const PostDominatorTree &getPostDomTree() const { return DT; }
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
@ -38,55 +78,8 @@ struct PostDominatorTree : public FunctionPass {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
inline const std::vector<BasicBlock*> &getRoots() const {
|
||||
return DT->getRoots();
|
||||
}
|
||||
|
||||
inline DomTreeNode *getRootNode() const {
|
||||
return DT->getRootNode();
|
||||
}
|
||||
|
||||
inline DomTreeNode *operator[](BasicBlock *BB) const {
|
||||
return DT->getNode(BB);
|
||||
}
|
||||
|
||||
inline DomTreeNode *getNode(BasicBlock *BB) const {
|
||||
return DT->getNode(BB);
|
||||
}
|
||||
|
||||
inline bool dominates(DomTreeNode* A, DomTreeNode* B) const {
|
||||
return DT->dominates(A, B);
|
||||
}
|
||||
|
||||
inline bool dominates(const BasicBlock* A, const BasicBlock* B) const {
|
||||
return DT->dominates(A, B);
|
||||
}
|
||||
|
||||
inline bool properlyDominates(const DomTreeNode* A, DomTreeNode* B) const {
|
||||
return DT->properlyDominates(A, B);
|
||||
}
|
||||
|
||||
inline bool properlyDominates(BasicBlock* A, BasicBlock* B) const {
|
||||
return DT->properlyDominates(A, B);
|
||||
}
|
||||
|
||||
inline BasicBlock *findNearestCommonDominator(BasicBlock *A, BasicBlock *B) {
|
||||
return DT->findNearestCommonDominator(A, B);
|
||||
}
|
||||
|
||||
inline const BasicBlock *findNearestCommonDominator(const BasicBlock *A,
|
||||
const BasicBlock *B) {
|
||||
return DT->findNearestCommonDominator(A, B);
|
||||
}
|
||||
|
||||
/// Get all nodes post-dominated by R, including R itself.
|
||||
void getDescendants(BasicBlock *R,
|
||||
SmallVectorImpl<BasicBlock *> &Result) const {
|
||||
DT->getDescendants(R, Result);
|
||||
}
|
||||
|
||||
void releaseMemory() override {
|
||||
DT->releaseMemory();
|
||||
DT.releaseMemory();
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const Module*) const override;
|
||||
|
113
contrib/llvm/include/llvm/Analysis/ProfileSummaryInfo.h
Normal file
113
contrib/llvm/include/llvm/Analysis/ProfileSummaryInfo.h
Normal file
@ -0,0 +1,113 @@
|
||||
//===- llvm/Analysis/ProfileSummaryInfo.h - profile summary ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a pass that provides access to profile summary
|
||||
// information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_PROFILE_SUMMARY_INFO_H
|
||||
#define LLVM_ANALYSIS_PROFILE_SUMMARY_INFO_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/ProfileSummary.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
class ProfileSummary;
|
||||
/// \brief Analysis providing profile information.
|
||||
///
|
||||
/// This is an immutable analysis pass that provides ability to query global
|
||||
/// (program-level) profile information. The main APIs are isHotCount and
|
||||
/// isColdCount that tells whether a given profile count is considered hot/cold
|
||||
/// based on the profile summary. This also provides convenience methods to
|
||||
/// check whether a function is hot or cold.
|
||||
|
||||
// FIXME: Provide convenience methods to determine hotness/coldness of other IR
|
||||
// units. This would require making this depend on BFI.
|
||||
class ProfileSummaryInfo {
|
||||
private:
|
||||
Module &M;
|
||||
std::unique_ptr<ProfileSummary> Summary;
|
||||
void computeSummary();
|
||||
void computeThresholds();
|
||||
// Count thresholds to answer isHotCount and isColdCount queries.
|
||||
Optional<uint64_t> HotCountThreshold, ColdCountThreshold;
|
||||
|
||||
public:
|
||||
ProfileSummaryInfo(Module &M) : M(M) {}
|
||||
ProfileSummaryInfo(ProfileSummaryInfo &&Arg)
|
||||
: M(Arg.M), Summary(std::move(Arg.Summary)) {}
|
||||
/// \brief Returns true if \p F is a hot function.
|
||||
bool isHotFunction(const Function *F);
|
||||
/// \brief Returns true if \p F is a cold function.
|
||||
bool isColdFunction(const Function *F);
|
||||
/// \brief Returns true if count \p C is considered hot.
|
||||
bool isHotCount(uint64_t C);
|
||||
/// \brief Returns true if count \p C is considered cold.
|
||||
bool isColdCount(uint64_t C);
|
||||
};
|
||||
|
||||
/// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
|
||||
class ProfileSummaryInfoWrapperPass : public ImmutablePass {
|
||||
std::unique_ptr<ProfileSummaryInfo> PSI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
ProfileSummaryInfoWrapperPass();
|
||||
|
||||
ProfileSummaryInfo *getPSI(Module &M);
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
/// An analysis pass based on the new PM to deliver ProfileSummaryInfo.
|
||||
class ProfileSummaryAnalysis
|
||||
: public AnalysisInfoMixin<ProfileSummaryAnalysis> {
|
||||
public:
|
||||
typedef ProfileSummaryInfo Result;
|
||||
|
||||
ProfileSummaryAnalysis() {}
|
||||
ProfileSummaryAnalysis(const ProfileSummaryAnalysis &Arg) {}
|
||||
ProfileSummaryAnalysis(ProfileSummaryAnalysis &&Arg) {}
|
||||
ProfileSummaryAnalysis &operator=(const ProfileSummaryAnalysis &RHS) {
|
||||
return *this;
|
||||
}
|
||||
ProfileSummaryAnalysis &operator=(ProfileSummaryAnalysis &&RHS) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Result run(Module &M, ModuleAnalysisManager &);
|
||||
|
||||
private:
|
||||
friend AnalysisInfoMixin<ProfileSummaryAnalysis>;
|
||||
static char PassID;
|
||||
};
|
||||
|
||||
/// \brief Printer pass that uses \c ProfileSummaryAnalysis.
|
||||
class ProfileSummaryPrinterPass
|
||||
: public PassInfoMixin<ProfileSummaryPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit ProfileSummaryPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -41,6 +41,7 @@
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@ -676,6 +677,22 @@ class RegionInfoBase {
|
||||
RegionInfoBase(const RegionInfoBase &) = delete;
|
||||
const RegionInfoBase &operator=(const RegionInfoBase &) = delete;
|
||||
|
||||
RegionInfoBase(RegionInfoBase &&Arg)
|
||||
: DT(std::move(Arg.DT)), PDT(std::move(Arg.PDT)), DF(std::move(Arg.DF)),
|
||||
TopLevelRegion(std::move(Arg.TopLevelRegion)),
|
||||
BBtoRegion(std::move(Arg.BBtoRegion)) {
|
||||
Arg.wipe();
|
||||
}
|
||||
RegionInfoBase &operator=(RegionInfoBase &&RHS) {
|
||||
DT = std::move(RHS.DT);
|
||||
PDT = std::move(RHS.PDT);
|
||||
DF = std::move(RHS.DF);
|
||||
TopLevelRegion = std::move(RHS.TopLevelRegion);
|
||||
BBtoRegion = std::move(RHS.BBtoRegion);
|
||||
RHS.wipe();
|
||||
return *this;
|
||||
}
|
||||
|
||||
DomTreeT *DT;
|
||||
PostDomTreeT *PDT;
|
||||
DomFrontierT *DF;
|
||||
@ -687,6 +704,18 @@ private:
|
||||
/// Map every BB to the smallest region, that contains BB.
|
||||
BBtoRegionMap BBtoRegion;
|
||||
|
||||
/// \brief Wipe this region tree's state without releasing any resources.
|
||||
///
|
||||
/// This is essentially a post-move helper only. It leaves the object in an
|
||||
/// assignable and destroyable state, but otherwise invalid.
|
||||
void wipe() {
|
||||
DT = nullptr;
|
||||
PDT = nullptr;
|
||||
DF = nullptr;
|
||||
TopLevelRegion = nullptr;
|
||||
BBtoRegion.clear();
|
||||
}
|
||||
|
||||
// Check whether the entries of BBtoRegion for the BBs of region
|
||||
// SR are correct. Triggers an assertion if not. Calls itself recursively for
|
||||
// subregions.
|
||||
@ -836,10 +865,19 @@ public:
|
||||
|
||||
class RegionInfo : public RegionInfoBase<RegionTraits<Function>> {
|
||||
public:
|
||||
typedef RegionInfoBase<RegionTraits<Function>> Base;
|
||||
|
||||
explicit RegionInfo();
|
||||
|
||||
~RegionInfo() override;
|
||||
|
||||
RegionInfo(RegionInfo &&Arg)
|
||||
: Base(std::move(static_cast<Base &>(Arg))) {}
|
||||
RegionInfo &operator=(RegionInfo &&RHS) {
|
||||
Base::operator=(std::move(static_cast<Base &>(RHS)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// updateStatistics - Update statistic about created regions.
|
||||
void updateStatistics(Region *R) final;
|
||||
|
||||
@ -884,6 +922,31 @@ public:
|
||||
//@}
|
||||
};
|
||||
|
||||
/// \brief Analysis pass that exposes the \c RegionInfo for a function.
|
||||
class RegionInfoAnalysis : public AnalysisInfoMixin<RegionInfoAnalysis> {
|
||||
friend AnalysisInfoMixin<RegionInfoAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef RegionInfo Result;
|
||||
|
||||
RegionInfo run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c RegionInfo.
|
||||
class RegionInfoPrinterPass : public PassInfoMixin<RegionInfoPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit RegionInfoPrinterPass(raw_ostream &OS);
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Verifier pass for the \c RegionInfo.
|
||||
struct RegionInfoVerifierPass : PassInfoMixin<RegionInfoVerifierPass> {
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline BasicBlock *
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "llvm/Analysis/PostDominators.h"
|
||||
#include "llvm/Analysis/RegionInfo.h"
|
||||
#include "llvm/Analysis/RegionIterator.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
@ -666,7 +665,7 @@ typename Tr::RegionT *RegionInfoBase<Tr>::createRegion(BlockT *entry,
|
||||
new RegionT(entry, exit, static_cast<RegionInfoT *>(this), DT);
|
||||
BBtoRegion.insert(std::make_pair(entry, region));
|
||||
|
||||
#ifdef XDEBUG
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
region->verifyRegion();
|
||||
#else
|
||||
DEBUG(region->verifyRegion());
|
||||
@ -765,7 +764,7 @@ void RegionInfoBase<Tr>::buildRegionsTree(DomTreeNodeT *N, RegionT *region) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XDEBUG
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
template <class Tr>
|
||||
bool RegionInfoBase<Tr>::VerifyRegionInfo = true;
|
||||
#else
|
||||
@ -799,7 +798,7 @@ void RegionInfoBase<Tr>::releaseMemory() {
|
||||
|
||||
template <class Tr>
|
||||
void RegionInfoBase<Tr>::verifyAnalysis() const {
|
||||
// Do only verify regions if explicitely activated using XDEBUG or
|
||||
// Do only verify regions if explicitely activated using EXPENSIVE_CHECKS or
|
||||
// -verify-region-info
|
||||
if (!RegionInfoBase<Tr>::VerifyRegionInfo)
|
||||
return;
|
||||
|
@ -23,17 +23,17 @@
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/IR/ConstantRange.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/IR/ValueMap.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
class APInt;
|
||||
@ -53,6 +53,7 @@ namespace llvm {
|
||||
class SCEVExpander;
|
||||
class SCEVPredicate;
|
||||
class SCEVUnknown;
|
||||
class Function;
|
||||
|
||||
template <> struct FoldingSetTrait<SCEV>;
|
||||
template <> struct FoldingSetTrait<SCEVPredicate>;
|
||||
@ -168,8 +169,8 @@ namespace llvm {
|
||||
static bool classof(const SCEV *S);
|
||||
};
|
||||
|
||||
/// SCEVPredicate - This class represents an assumption made using SCEV
|
||||
/// expressions which can be checked at run-time.
|
||||
/// This class represents an assumption made using SCEV expressions which can
|
||||
/// be checked at run-time.
|
||||
class SCEVPredicate : public FoldingSetNode {
|
||||
friend struct FoldingSetTrait<SCEVPredicate>;
|
||||
|
||||
@ -178,7 +179,7 @@ namespace llvm {
|
||||
FoldingSetNodeIDRef FastID;
|
||||
|
||||
public:
|
||||
enum SCEVPredicateKind { P_Union, P_Equal };
|
||||
enum SCEVPredicateKind { P_Union, P_Equal, P_Wrap };
|
||||
|
||||
protected:
|
||||
SCEVPredicateKind Kind;
|
||||
@ -191,23 +192,23 @@ namespace llvm {
|
||||
|
||||
SCEVPredicateKind getKind() const { return Kind; }
|
||||
|
||||
/// \brief Returns the estimated complexity of this predicate.
|
||||
/// This is roughly measured in the number of run-time checks required.
|
||||
/// Returns the estimated complexity of this predicate. This is roughly
|
||||
/// measured in the number of run-time checks required.
|
||||
virtual unsigned getComplexity() const { return 1; }
|
||||
|
||||
/// \brief Returns true if the predicate is always true. This means that no
|
||||
/// Returns true if the predicate is always true. This means that no
|
||||
/// assumptions were made and nothing needs to be checked at run-time.
|
||||
virtual bool isAlwaysTrue() const = 0;
|
||||
|
||||
/// \brief Returns true if this predicate implies \p N.
|
||||
/// Returns true if this predicate implies \p N.
|
||||
virtual bool implies(const SCEVPredicate *N) const = 0;
|
||||
|
||||
/// \brief Prints a textual representation of this predicate with an
|
||||
/// indentation of \p Depth.
|
||||
/// Prints a textual representation of this predicate with an indentation of
|
||||
/// \p Depth.
|
||||
virtual void print(raw_ostream &OS, unsigned Depth = 0) const = 0;
|
||||
|
||||
/// \brief Returns the SCEV to which this predicate applies, or nullptr
|
||||
/// if this is a SCEVUnionPredicate.
|
||||
/// Returns the SCEV to which this predicate applies, or nullptr if this is
|
||||
/// a SCEVUnionPredicate.
|
||||
virtual const SCEV *getExpr() const = 0;
|
||||
};
|
||||
|
||||
@ -236,10 +237,9 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
/// SCEVEqualPredicate - This class represents an assumption that two SCEV
|
||||
/// expressions are equal, and this can be checked at run-time. We assume
|
||||
/// that the left hand side is a SCEVUnknown and the right hand side a
|
||||
/// constant.
|
||||
/// This class represents an assumption that two SCEV expressions are equal,
|
||||
/// and this can be checked at run-time. We assume that the left hand side is
|
||||
/// a SCEVUnknown and the right hand side a constant.
|
||||
class SCEVEqualPredicate final : public SCEVPredicate {
|
||||
/// We assume that LHS == RHS, where LHS is a SCEVUnknown and RHS a
|
||||
/// constant.
|
||||
@ -256,10 +256,10 @@ namespace llvm {
|
||||
bool isAlwaysTrue() const override;
|
||||
const SCEV *getExpr() const override;
|
||||
|
||||
/// \brief Returns the left hand side of the equality.
|
||||
/// Returns the left hand side of the equality.
|
||||
const SCEVUnknown *getLHS() const { return LHS; }
|
||||
|
||||
/// \brief Returns the right hand side of the equality.
|
||||
/// Returns the right hand side of the equality.
|
||||
const SCEVConstant *getRHS() const { return RHS; }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
@ -268,9 +268,107 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
/// SCEVUnionPredicate - This class represents a composition of other
|
||||
/// SCEV predicates, and is the class that most clients will interact with.
|
||||
/// This is equivalent to a logical "AND" of all the predicates in the union.
|
||||
/// This class represents an assumption made on an AddRec expression. Given an
|
||||
/// affine AddRec expression {a,+,b}, we assume that it has the nssw or nusw
|
||||
/// flags (defined below) in the first X iterations of the loop, where X is a
|
||||
/// SCEV expression returned by getPredicatedBackedgeTakenCount).
|
||||
///
|
||||
/// Note that this does not imply that X is equal to the backedge taken
|
||||
/// count. This means that if we have a nusw predicate for i32 {0,+,1} with a
|
||||
/// predicated backedge taken count of X, we only guarantee that {0,+,1} has
|
||||
/// nusw in the first X iterations. {0,+,1} may still wrap in the loop if we
|
||||
/// have more than X iterations.
|
||||
class SCEVWrapPredicate final : public SCEVPredicate {
|
||||
public:
|
||||
/// Similar to SCEV::NoWrapFlags, but with slightly different semantics
|
||||
/// for FlagNUSW. The increment is considered to be signed, and a + b
|
||||
/// (where b is the increment) is considered to wrap if:
|
||||
/// zext(a + b) != zext(a) + sext(b)
|
||||
///
|
||||
/// If Signed is a function that takes an n-bit tuple and maps to the
|
||||
/// integer domain as the tuples value interpreted as twos complement,
|
||||
/// and Unsigned a function that takes an n-bit tuple and maps to the
|
||||
/// integer domain as as the base two value of input tuple, then a + b
|
||||
/// has IncrementNUSW iff:
|
||||
///
|
||||
/// 0 <= Unsigned(a) + Signed(b) < 2^n
|
||||
///
|
||||
/// The IncrementNSSW flag has identical semantics with SCEV::FlagNSW.
|
||||
///
|
||||
/// Note that the IncrementNUSW flag is not commutative: if base + inc
|
||||
/// has IncrementNUSW, then inc + base doesn't neccessarily have this
|
||||
/// property. The reason for this is that this is used for sign/zero
|
||||
/// extending affine AddRec SCEV expressions when a SCEVWrapPredicate is
|
||||
/// assumed. A {base,+,inc} expression is already non-commutative with
|
||||
/// regards to base and inc, since it is interpreted as:
|
||||
/// (((base + inc) + inc) + inc) ...
|
||||
enum IncrementWrapFlags {
|
||||
IncrementAnyWrap = 0, // No guarantee.
|
||||
IncrementNUSW = (1 << 0), // No unsigned with signed increment wrap.
|
||||
IncrementNSSW = (1 << 1), // No signed with signed increment wrap
|
||||
// (equivalent with SCEV::NSW)
|
||||
IncrementNoWrapMask = (1 << 2) - 1
|
||||
};
|
||||
|
||||
/// Convenient IncrementWrapFlags manipulation methods.
|
||||
static SCEVWrapPredicate::IncrementWrapFlags LLVM_ATTRIBUTE_UNUSED_RESULT
|
||||
clearFlags(SCEVWrapPredicate::IncrementWrapFlags Flags,
|
||||
SCEVWrapPredicate::IncrementWrapFlags OffFlags) {
|
||||
assert((Flags & IncrementNoWrapMask) == Flags && "Invalid flags value!");
|
||||
assert((OffFlags & IncrementNoWrapMask) == OffFlags &&
|
||||
"Invalid flags value!");
|
||||
return (SCEVWrapPredicate::IncrementWrapFlags)(Flags & ~OffFlags);
|
||||
}
|
||||
|
||||
static SCEVWrapPredicate::IncrementWrapFlags LLVM_ATTRIBUTE_UNUSED_RESULT
|
||||
maskFlags(SCEVWrapPredicate::IncrementWrapFlags Flags, int Mask) {
|
||||
assert((Flags & IncrementNoWrapMask) == Flags && "Invalid flags value!");
|
||||
assert((Mask & IncrementNoWrapMask) == Mask && "Invalid mask value!");
|
||||
|
||||
return (SCEVWrapPredicate::IncrementWrapFlags)(Flags & Mask);
|
||||
}
|
||||
|
||||
static SCEVWrapPredicate::IncrementWrapFlags LLVM_ATTRIBUTE_UNUSED_RESULT
|
||||
setFlags(SCEVWrapPredicate::IncrementWrapFlags Flags,
|
||||
SCEVWrapPredicate::IncrementWrapFlags OnFlags) {
|
||||
assert((Flags & IncrementNoWrapMask) == Flags && "Invalid flags value!");
|
||||
assert((OnFlags & IncrementNoWrapMask) == OnFlags &&
|
||||
"Invalid flags value!");
|
||||
|
||||
return (SCEVWrapPredicate::IncrementWrapFlags)(Flags | OnFlags);
|
||||
}
|
||||
|
||||
/// Returns the set of SCEVWrapPredicate no wrap flags implied by a
|
||||
/// SCEVAddRecExpr.
|
||||
static SCEVWrapPredicate::IncrementWrapFlags
|
||||
getImpliedFlags(const SCEVAddRecExpr *AR, ScalarEvolution &SE);
|
||||
|
||||
private:
|
||||
const SCEVAddRecExpr *AR;
|
||||
IncrementWrapFlags Flags;
|
||||
|
||||
public:
|
||||
explicit SCEVWrapPredicate(const FoldingSetNodeIDRef ID,
|
||||
const SCEVAddRecExpr *AR,
|
||||
IncrementWrapFlags Flags);
|
||||
|
||||
/// Returns the set assumed no overflow flags.
|
||||
IncrementWrapFlags getFlags() const { return Flags; }
|
||||
/// Implementation of the SCEVPredicate interface
|
||||
const SCEV *getExpr() const override;
|
||||
bool implies(const SCEVPredicate *N) const override;
|
||||
void print(raw_ostream &OS, unsigned Depth = 0) const override;
|
||||
bool isAlwaysTrue() const override;
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEVPredicate *P) {
|
||||
return P->getKind() == P_Wrap;
|
||||
}
|
||||
};
|
||||
|
||||
/// This class represents a composition of other SCEV predicates, and is the
|
||||
/// class that most clients will interact with. This is equivalent to a
|
||||
/// logical "AND" of all the predicates in the union.
|
||||
class SCEVUnionPredicate final : public SCEVPredicate {
|
||||
private:
|
||||
typedef DenseMap<const SCEV *, SmallVector<const SCEVPredicate *, 4>>
|
||||
@ -288,11 +386,11 @@ namespace llvm {
|
||||
return Preds;
|
||||
}
|
||||
|
||||
/// \brief Adds a predicate to this union.
|
||||
/// Adds a predicate to this union.
|
||||
void add(const SCEVPredicate *N);
|
||||
|
||||
/// \brief Returns a reference to a vector containing all predicates
|
||||
/// which apply to \p Expr.
|
||||
/// Returns a reference to a vector containing all predicates which apply to
|
||||
/// \p Expr.
|
||||
ArrayRef<const SCEVPredicate *> getPredicatesForExpr(const SCEV *Expr);
|
||||
|
||||
/// Implementation of the SCEVPredicate interface
|
||||
@ -301,8 +399,8 @@ namespace llvm {
|
||||
void print(raw_ostream &OS, unsigned Depth) const override;
|
||||
const SCEV *getExpr() const override;
|
||||
|
||||
/// \brief We estimate the complexity of a union predicate as the size
|
||||
/// number of predicates in the union.
|
||||
/// We estimate the complexity of a union predicate as the size number of
|
||||
/// predicates in the union.
|
||||
unsigned getComplexity() const override { return Preds.size(); }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
@ -364,6 +462,12 @@ namespace llvm {
|
||||
///
|
||||
Function &F;
|
||||
|
||||
/// Does the module have any calls to the llvm.experimental.guard intrinsic
|
||||
/// at all? If this is false, we avoid doing work that will only help if
|
||||
/// thare are guards present in the IR.
|
||||
///
|
||||
bool HasGuards;
|
||||
|
||||
/// The target library information for the target we are targeting.
|
||||
///
|
||||
TargetLibraryInfo &TLI;
|
||||
@ -382,6 +486,21 @@ namespace llvm {
|
||||
/// This SCEV is used to represent unknown trip counts and things.
|
||||
std::unique_ptr<SCEVCouldNotCompute> CouldNotCompute;
|
||||
|
||||
/// The typedef for HasRecMap.
|
||||
///
|
||||
typedef DenseMap<const SCEV *, bool> HasRecMapType;
|
||||
|
||||
/// This is a cache to record whether a SCEV contains any scAddRecExpr.
|
||||
HasRecMapType HasRecMap;
|
||||
|
||||
/// The typedef for ExprValueMap.
|
||||
///
|
||||
typedef DenseMap<const SCEV *, SetVector<Value *>> ExprValueMapType;
|
||||
|
||||
/// ExprValueMap -- This map records the original values from which
|
||||
/// the SCEV expr is generated from.
|
||||
ExprValueMapType ExprValueMap;
|
||||
|
||||
/// The typedef for ValueExprMap.
|
||||
///
|
||||
typedef DenseMap<SCEVCallbackVH, const SCEV *, DenseMapInfo<Value *> >
|
||||
@ -410,9 +529,14 @@ namespace llvm {
|
||||
const SCEV *Exact;
|
||||
const SCEV *Max;
|
||||
|
||||
/// A predicate union guard for this ExitLimit. The result is only
|
||||
/// valid if this predicate evaluates to 'true' at run-time.
|
||||
SCEVUnionPredicate Pred;
|
||||
|
||||
/*implicit*/ ExitLimit(const SCEV *E) : Exact(E), Max(E) {}
|
||||
|
||||
ExitLimit(const SCEV *E, const SCEV *M) : Exact(E), Max(M) {
|
||||
ExitLimit(const SCEV *E, const SCEV *M, SCEVUnionPredicate &P)
|
||||
: Exact(E), Max(M), Pred(P) {
|
||||
assert((isa<SCEVCouldNotCompute>(Exact) ||
|
||||
!isa<SCEVCouldNotCompute>(Max)) &&
|
||||
"Exact is not allowed to be less precise than Max");
|
||||
@ -424,30 +548,147 @@ namespace llvm {
|
||||
return !isa<SCEVCouldNotCompute>(Exact) ||
|
||||
!isa<SCEVCouldNotCompute>(Max);
|
||||
}
|
||||
|
||||
/// Test whether this ExitLimit contains all information.
|
||||
bool hasFullInfo() const { return !isa<SCEVCouldNotCompute>(Exact); }
|
||||
};
|
||||
|
||||
/// Forward declaration of ExitNotTakenExtras
|
||||
struct ExitNotTakenExtras;
|
||||
|
||||
/// Information about the number of times a particular loop exit may be
|
||||
/// reached before exiting the loop.
|
||||
struct ExitNotTakenInfo {
|
||||
AssertingVH<BasicBlock> ExitingBlock;
|
||||
const SCEV *ExactNotTaken;
|
||||
PointerIntPair<ExitNotTakenInfo*, 1> NextExit;
|
||||
|
||||
ExitNotTakenInfo() : ExitingBlock(nullptr), ExactNotTaken(nullptr) {}
|
||||
ExitNotTakenExtras *ExtraInfo;
|
||||
bool Complete;
|
||||
|
||||
ExitNotTakenInfo()
|
||||
: ExitingBlock(nullptr), ExactNotTaken(nullptr), ExtraInfo(nullptr),
|
||||
Complete(true) {}
|
||||
|
||||
ExitNotTakenInfo(BasicBlock *ExitBlock, const SCEV *Expr,
|
||||
ExitNotTakenExtras *Ptr)
|
||||
: ExitingBlock(ExitBlock), ExactNotTaken(Expr), ExtraInfo(Ptr),
|
||||
Complete(true) {}
|
||||
|
||||
/// Return true if all loop exits are computable.
|
||||
bool isCompleteList() const {
|
||||
return NextExit.getInt() == 0;
|
||||
bool isCompleteList() const { return Complete; }
|
||||
|
||||
/// Sets the incomplete property, indicating that one of the loop exits
|
||||
/// doesn't have a corresponding ExitNotTakenInfo entry.
|
||||
void setIncomplete() { Complete = false; }
|
||||
|
||||
/// Returns a pointer to the predicate associated with this information,
|
||||
/// or nullptr if this doesn't exist (meaning always true).
|
||||
SCEVUnionPredicate *getPred() const {
|
||||
if (ExtraInfo)
|
||||
return &ExtraInfo->Pred;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setIncomplete() { NextExit.setInt(1); }
|
||||
|
||||
/// Return a pointer to the next exit's not-taken info.
|
||||
ExitNotTakenInfo *getNextExit() const {
|
||||
return NextExit.getPointer();
|
||||
/// Return true if the SCEV predicate associated with this information
|
||||
/// is always true.
|
||||
bool hasAlwaysTruePred() const {
|
||||
return !getPred() || getPred()->isAlwaysTrue();
|
||||
}
|
||||
|
||||
void setNextExit(ExitNotTakenInfo *ENT) { NextExit.setPointer(ENT); }
|
||||
/// Defines a simple forward iterator for ExitNotTakenInfo.
|
||||
class ExitNotTakenInfoIterator
|
||||
: public std::iterator<std::forward_iterator_tag, ExitNotTakenInfo> {
|
||||
const ExitNotTakenInfo *Start;
|
||||
unsigned Position;
|
||||
|
||||
public:
|
||||
ExitNotTakenInfoIterator(const ExitNotTakenInfo *Start,
|
||||
unsigned Position)
|
||||
: Start(Start), Position(Position) {}
|
||||
|
||||
const ExitNotTakenInfo &operator*() const {
|
||||
if (Position == 0)
|
||||
return *Start;
|
||||
|
||||
return Start->ExtraInfo->Exits[Position - 1];
|
||||
}
|
||||
|
||||
const ExitNotTakenInfo *operator->() const {
|
||||
if (Position == 0)
|
||||
return Start;
|
||||
|
||||
return &Start->ExtraInfo->Exits[Position - 1];
|
||||
}
|
||||
|
||||
bool operator==(const ExitNotTakenInfoIterator &RHS) const {
|
||||
return Start == RHS.Start && Position == RHS.Position;
|
||||
}
|
||||
|
||||
bool operator!=(const ExitNotTakenInfoIterator &RHS) const {
|
||||
return Start != RHS.Start || Position != RHS.Position;
|
||||
}
|
||||
|
||||
ExitNotTakenInfoIterator &operator++() { // Preincrement
|
||||
if (!Start)
|
||||
return *this;
|
||||
|
||||
unsigned Elements =
|
||||
Start->ExtraInfo ? Start->ExtraInfo->Exits.size() + 1 : 1;
|
||||
|
||||
++Position;
|
||||
|
||||
// We've run out of elements.
|
||||
if (Position == Elements) {
|
||||
Start = nullptr;
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
ExitNotTakenInfoIterator operator++(int) { // Postincrement
|
||||
ExitNotTakenInfoIterator Tmp = *this;
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// Iterators
|
||||
ExitNotTakenInfoIterator begin() const {
|
||||
return ExitNotTakenInfoIterator(this, 0);
|
||||
}
|
||||
ExitNotTakenInfoIterator end() const {
|
||||
return ExitNotTakenInfoIterator(nullptr, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/// Describes the extra information that a ExitNotTakenInfo can have.
|
||||
struct ExitNotTakenExtras {
|
||||
/// The predicate associated with the ExitNotTakenInfo struct.
|
||||
SCEVUnionPredicate Pred;
|
||||
|
||||
/// The extra exits in the loop. Only the ExitNotTakenExtras structure
|
||||
/// pointed to by the first ExitNotTakenInfo struct (associated with the
|
||||
/// first loop exit) will populate this vector to prevent having
|
||||
/// redundant information.
|
||||
SmallVector<ExitNotTakenInfo, 4> Exits;
|
||||
};
|
||||
|
||||
/// A struct containing the information attached to a backedge.
|
||||
struct EdgeInfo {
|
||||
EdgeInfo(BasicBlock *Block, const SCEV *Taken, SCEVUnionPredicate &P) :
|
||||
ExitBlock(Block), Taken(Taken), Pred(std::move(P)) {}
|
||||
|
||||
/// The exit basic block.
|
||||
BasicBlock *ExitBlock;
|
||||
|
||||
/// The (exact) number of time we take the edge back.
|
||||
const SCEV *Taken;
|
||||
|
||||
/// The SCEV predicated associated with Taken. If Pred doesn't evaluate
|
||||
/// to true, the information in Taken is not valid (or equivalent with
|
||||
/// a CouldNotCompute.
|
||||
SCEVUnionPredicate Pred;
|
||||
};
|
||||
|
||||
/// Information about the backedge-taken count of a loop. This currently
|
||||
@ -459,16 +700,16 @@ namespace llvm {
|
||||
ExitNotTakenInfo ExitNotTaken;
|
||||
|
||||
/// An expression indicating the least maximum backedge-taken count of the
|
||||
/// loop that is known, or a SCEVCouldNotCompute.
|
||||
/// loop that is known, or a SCEVCouldNotCompute. This expression is only
|
||||
/// valid if the predicates associated with all loop exits are true.
|
||||
const SCEV *Max;
|
||||
|
||||
public:
|
||||
BackedgeTakenInfo() : Max(nullptr) {}
|
||||
|
||||
/// Initialize BackedgeTakenInfo from a list of exact exit counts.
|
||||
BackedgeTakenInfo(
|
||||
SmallVectorImpl< std::pair<BasicBlock *, const SCEV *> > &ExitCounts,
|
||||
bool Complete, const SCEV *MaxCount);
|
||||
BackedgeTakenInfo(SmallVectorImpl<EdgeInfo> &ExitCounts, bool Complete,
|
||||
const SCEV *MaxCount);
|
||||
|
||||
/// Test whether this BackedgeTakenInfo contains any computed information,
|
||||
/// or whether it's all SCEVCouldNotCompute values.
|
||||
@ -476,11 +717,27 @@ namespace llvm {
|
||||
return ExitNotTaken.ExitingBlock || !isa<SCEVCouldNotCompute>(Max);
|
||||
}
|
||||
|
||||
/// Test whether this BackedgeTakenInfo contains complete information.
|
||||
bool hasFullInfo() const { return ExitNotTaken.isCompleteList(); }
|
||||
|
||||
/// Return an expression indicating the exact backedge-taken count of the
|
||||
/// loop if it is known, or SCEVCouldNotCompute otherwise. This is the
|
||||
/// loop if it is known or SCEVCouldNotCompute otherwise. This is the
|
||||
/// number of times the loop header can be guaranteed to execute, minus
|
||||
/// one.
|
||||
const SCEV *getExact(ScalarEvolution *SE) const;
|
||||
///
|
||||
/// If the SCEV predicate associated with the answer can be different
|
||||
/// from AlwaysTrue, we must add a (non null) Predicates argument.
|
||||
/// The SCEV predicate associated with the answer will be added to
|
||||
/// Predicates. A run-time check needs to be emitted for the SCEV
|
||||
/// predicate in order for the answer to be valid.
|
||||
///
|
||||
/// Note that we should always know if we need to pass a predicate
|
||||
/// argument or not from the way the ExitCounts vector was computed.
|
||||
/// If we allowed SCEV predicates to be generated when populating this
|
||||
/// vector, this information can contain them and therefore a
|
||||
/// SCEVPredicate argument should be added to getExact.
|
||||
const SCEV *getExact(ScalarEvolution *SE,
|
||||
SCEVUnionPredicate *Predicates = nullptr) const;
|
||||
|
||||
/// Return the number of times this loop exit may fall through to the back
|
||||
/// edge, or SCEVCouldNotCompute. The loop is guaranteed not to exit via
|
||||
@ -501,7 +758,11 @@ namespace llvm {
|
||||
|
||||
/// Cache the backedge-taken count of the loops for this function as they
|
||||
/// are computed.
|
||||
DenseMap<const Loop*, BackedgeTakenInfo> BackedgeTakenCounts;
|
||||
DenseMap<const Loop *, BackedgeTakenInfo> BackedgeTakenCounts;
|
||||
|
||||
/// Cache the predicated backedge-taken count of the loops for this
|
||||
/// function as they are computed.
|
||||
DenseMap<const Loop *, BackedgeTakenInfo> PredicatedBackedgeTakenCounts;
|
||||
|
||||
/// This map contains entries for all of the PHI instructions that we
|
||||
/// attempt to compute constant evolutions for. This allows us to avoid
|
||||
@ -520,6 +781,16 @@ namespace llvm {
|
||||
SmallVector<PointerIntPair<const Loop *, 2, LoopDisposition>, 2>>
|
||||
LoopDispositions;
|
||||
|
||||
/// Cache for \c loopHasNoAbnormalExits.
|
||||
DenseMap<const Loop *, bool> LoopHasNoAbnormalExits;
|
||||
|
||||
/// Returns true if \p L contains no instruction that can abnormally exit
|
||||
/// the loop (i.e. via throwing an exception, by terminating the thread
|
||||
/// cleanly or by infinite looping in a called function). Strictly
|
||||
/// speaking, the last one is not leaving the loop, but is identical to
|
||||
/// leaving the loop for reasoning about undefined behavior.
|
||||
bool loopHasNoAbnormalExits(const Loop *L);
|
||||
|
||||
/// Compute a LoopDisposition value.
|
||||
LoopDisposition computeLoopDisposition(const SCEV *S, const Loop *L);
|
||||
|
||||
@ -547,8 +818,7 @@ namespace llvm {
|
||||
DenseMap<const SCEV *, ConstantRange> &Cache =
|
||||
Hint == HINT_RANGE_UNSIGNED ? UnsignedRanges : SignedRanges;
|
||||
|
||||
std::pair<DenseMap<const SCEV *, ConstantRange>::iterator, bool> Pair =
|
||||
Cache.insert(std::make_pair(S, CR));
|
||||
auto Pair = Cache.insert({S, CR});
|
||||
if (!Pair.second)
|
||||
Pair.first->second = CR;
|
||||
return Pair.first->second;
|
||||
@ -557,6 +827,19 @@ namespace llvm {
|
||||
/// Determine the range for a particular SCEV.
|
||||
ConstantRange getRange(const SCEV *S, RangeSignHint Hint);
|
||||
|
||||
/// Determines the range for the affine SCEVAddRecExpr {\p Start,+,\p Stop}.
|
||||
/// Helper for \c getRange.
|
||||
ConstantRange getRangeForAffineAR(const SCEV *Start, const SCEV *Stop,
|
||||
const SCEV *MaxBECount,
|
||||
unsigned BitWidth);
|
||||
|
||||
/// Try to compute a range for the affine SCEVAddRecExpr {\p Start,+,\p
|
||||
/// Stop} by "factoring out" a ternary expression from the add recurrence.
|
||||
/// Helper called by \c getRange.
|
||||
ConstantRange getRangeViaFactoring(const SCEV *Start, const SCEV *Stop,
|
||||
const SCEV *MaxBECount,
|
||||
unsigned BitWidth);
|
||||
|
||||
/// We know that there is no SCEV for the specified value. Analyze the
|
||||
/// expression.
|
||||
const SCEV *createSCEV(Value *V);
|
||||
@ -588,36 +871,59 @@ namespace llvm {
|
||||
/// This looks up computed SCEV values for all instructions that depend on
|
||||
/// the given instruction and removes them from the ValueExprMap map if they
|
||||
/// reference SymName. This is used during PHI resolution.
|
||||
void ForgetSymbolicName(Instruction *I, const SCEV *SymName);
|
||||
void forgetSymbolicName(Instruction *I, const SCEV *SymName);
|
||||
|
||||
/// Return the BackedgeTakenInfo for the given loop, lazily computing new
|
||||
/// values if the loop hasn't been analyzed yet.
|
||||
/// values if the loop hasn't been analyzed yet. The returned result is
|
||||
/// guaranteed not to be predicated.
|
||||
const BackedgeTakenInfo &getBackedgeTakenInfo(const Loop *L);
|
||||
|
||||
/// Similar to getBackedgeTakenInfo, but will add predicates as required
|
||||
/// with the purpose of returning complete information.
|
||||
const BackedgeTakenInfo &getPredicatedBackedgeTakenInfo(const Loop *L);
|
||||
|
||||
/// Compute the number of times the specified loop will iterate.
|
||||
BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L);
|
||||
/// If AllowPredicates is set, we will create new SCEV predicates as
|
||||
/// necessary in order to return an exact answer.
|
||||
BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will
|
||||
/// execute if it exits via the specified block.
|
||||
ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock);
|
||||
/// execute if it exits via the specified block. If AllowPredicates is set,
|
||||
/// this call will try to use a minimal set of SCEV predicates in order to
|
||||
/// return an exact answer.
|
||||
ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will
|
||||
/// execute if its exit condition were a conditional branch of ExitCond,
|
||||
/// TBB, and FBB.
|
||||
///
|
||||
/// \p ControlsExit is true if ExitCond directly controls the exit
|
||||
/// branch. In this case, we can assume that the loop exits only if the
|
||||
/// condition is true and can infer that failing to meet the condition prior
|
||||
/// to integer wraparound results in undefined behavior.
|
||||
///
|
||||
/// If \p AllowPredicates is set, this call will try to use a minimal set of
|
||||
/// SCEV predicates in order to return an exact answer.
|
||||
ExitLimit computeExitLimitFromCond(const Loop *L,
|
||||
Value *ExitCond,
|
||||
BasicBlock *TBB,
|
||||
BasicBlock *FBB,
|
||||
bool IsSubExpr);
|
||||
bool ControlsExit,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will
|
||||
/// execute if its exit condition were a conditional branch of the ICmpInst
|
||||
/// ExitCond, TBB, and FBB.
|
||||
/// ExitCond, TBB, and FBB. If AllowPredicates is set, this call will try
|
||||
/// to use a minimal set of SCEV predicates in order to return an exact
|
||||
/// answer.
|
||||
ExitLimit computeExitLimitFromICmp(const Loop *L,
|
||||
ICmpInst *ExitCond,
|
||||
BasicBlock *TBB,
|
||||
BasicBlock *FBB,
|
||||
bool IsSubExpr);
|
||||
bool IsSubExpr,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will
|
||||
/// execute if its exit condition were a switch with a single exiting case
|
||||
@ -655,20 +961,35 @@ namespace llvm {
|
||||
|
||||
/// Return the number of times an exit condition comparing the specified
|
||||
/// value to zero will execute. If not computable, return CouldNotCompute.
|
||||
ExitLimit HowFarToZero(const SCEV *V, const Loop *L, bool IsSubExpr);
|
||||
/// If AllowPredicates is set, this call will try to use a minimal set of
|
||||
/// SCEV predicates in order to return an exact answer.
|
||||
ExitLimit howFarToZero(const SCEV *V, const Loop *L, bool IsSubExpr,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
/// Return the number of times an exit condition checking the specified
|
||||
/// value for nonzero will execute. If not computable, return
|
||||
/// CouldNotCompute.
|
||||
ExitLimit HowFarToNonZero(const SCEV *V, const Loop *L);
|
||||
ExitLimit howFarToNonZero(const SCEV *V, const Loop *L);
|
||||
|
||||
/// Return the number of times an exit condition containing the specified
|
||||
/// less-than comparison will execute. If not computable, return
|
||||
/// CouldNotCompute. isSigned specifies whether the less-than is signed.
|
||||
ExitLimit HowManyLessThans(const SCEV *LHS, const SCEV *RHS,
|
||||
const Loop *L, bool isSigned, bool IsSubExpr);
|
||||
ExitLimit HowManyGreaterThans(const SCEV *LHS, const SCEV *RHS,
|
||||
const Loop *L, bool isSigned, bool IsSubExpr);
|
||||
/// CouldNotCompute.
|
||||
///
|
||||
/// \p isSigned specifies whether the less-than is signed.
|
||||
///
|
||||
/// \p ControlsExit is true when the LHS < RHS condition directly controls
|
||||
/// the branch (loops exits only if condition is true). In this case, we can
|
||||
/// use NoWrapFlags to skip overflow checks.
|
||||
///
|
||||
/// If \p AllowPredicates is set, this call will try to use a minimal set of
|
||||
/// SCEV predicates in order to return an exact answer.
|
||||
ExitLimit howManyLessThans(const SCEV *LHS, const SCEV *RHS, const Loop *L,
|
||||
bool isSigned, bool ControlsExit,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
ExitLimit howManyGreaterThans(const SCEV *LHS, const SCEV *RHS,
|
||||
const Loop *L, bool isSigned, bool IsSubExpr,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
/// Return a predecessor of BB (which may not be an immediate predecessor)
|
||||
/// which has exactly one successor from which BB is reachable, or null if
|
||||
@ -707,12 +1028,18 @@ namespace llvm {
|
||||
|
||||
/// Test whether the condition described by Pred, LHS, and RHS is true
|
||||
/// whenever the condition described by Pred, FoundLHS, and FoundRHS is
|
||||
/// true. Utility function used by isImpliedCondOperands.
|
||||
/// true. Utility function used by isImpliedCondOperands. Tries to get
|
||||
/// cases like "X `sgt` 0 => X - 1 `sgt` -1".
|
||||
bool isImpliedCondOperandsViaRanges(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS,
|
||||
const SCEV *FoundLHS,
|
||||
const SCEV *FoundRHS);
|
||||
|
||||
/// Return true if the condition denoted by \p LHS \p Pred \p RHS is implied
|
||||
/// by a call to \c @llvm.experimental.guard in \p BB.
|
||||
bool isImpliedViaGuard(BasicBlock *BB, ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS);
|
||||
|
||||
/// Test whether the condition described by Pred, LHS, and RHS is true
|
||||
/// whenever the condition described by Pred, FoundLHS, and FoundRHS is
|
||||
/// true.
|
||||
@ -733,8 +1060,8 @@ namespace llvm {
|
||||
/// Test if the given expression is known to satisfy the condition described
|
||||
/// by Pred and the known constant ranges of LHS and RHS.
|
||||
///
|
||||
bool isKnownPredicateWithRanges(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS);
|
||||
bool isKnownPredicateViaConstantRanges(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS);
|
||||
|
||||
/// Try to prove the condition described by "LHS Pred RHS" by ruling out
|
||||
/// integer overflow.
|
||||
@ -778,6 +1105,9 @@ namespace llvm {
|
||||
bool proveNoWrapByVaryingStart(const SCEV *Start, const SCEV *Step,
|
||||
const Loop *L);
|
||||
|
||||
/// Try to prove NSW or NUW on \p AR relying on ConstantRange manipulation.
|
||||
SCEV::NoWrapFlags proveNoWrapViaConstantRanges(const SCEVAddRecExpr *AR);
|
||||
|
||||
bool isMonotonicPredicateImpl(const SCEVAddRecExpr *LHS,
|
||||
ICmpInst::Predicate Pred, bool &Increasing);
|
||||
|
||||
@ -793,11 +1123,35 @@ namespace llvm {
|
||||
bool isMonotonicPredicate(const SCEVAddRecExpr *LHS,
|
||||
ICmpInst::Predicate Pred, bool &Increasing);
|
||||
|
||||
// Return SCEV no-wrap flags that can be proven based on reasoning
|
||||
// about how poison produced from no-wrap flags on this value
|
||||
// (e.g. a nuw add) would trigger undefined behavior on overflow.
|
||||
/// Return SCEV no-wrap flags that can be proven based on reasoning about
|
||||
/// how poison produced from no-wrap flags on this value (e.g. a nuw add)
|
||||
/// would trigger undefined behavior on overflow.
|
||||
SCEV::NoWrapFlags getNoWrapFlagsFromUB(const Value *V);
|
||||
|
||||
/// Return true if the SCEV corresponding to \p I is never poison. Proving
|
||||
/// this is more complex than proving that just \p I is never poison, since
|
||||
/// SCEV commons expressions across control flow, and you can have cases
|
||||
/// like:
|
||||
///
|
||||
/// idx0 = a + b;
|
||||
/// ptr[idx0] = 100;
|
||||
/// if (<condition>) {
|
||||
/// idx1 = a +nsw b;
|
||||
/// ptr[idx1] = 200;
|
||||
/// }
|
||||
///
|
||||
/// where the SCEV expression (+ a b) is guaranteed to not be poison (and
|
||||
/// hence not sign-overflow) only if "<condition>" is true. Since both
|
||||
/// `idx0` and `idx1` will be mapped to the same SCEV expression, (+ a b),
|
||||
/// it is not okay to annotate (+ a b) with <nsw> in the above example.
|
||||
bool isSCEVExprNeverPoison(const Instruction *I);
|
||||
|
||||
/// This is like \c isSCEVExprNeverPoison but it specifically works for
|
||||
/// instructions that will get mapped to SCEV add recurrences. Return true
|
||||
/// if \p I will never generate poison under the assumption that \p I is an
|
||||
/// add recurrence on the loop \p L.
|
||||
bool isAddRecNeverPoison(const Instruction *I, const Loop *L);
|
||||
|
||||
public:
|
||||
ScalarEvolution(Function &F, TargetLibraryInfo &TLI, AssumptionCache &AC,
|
||||
DominatorTree &DT, LoopInfo &LI);
|
||||
@ -821,6 +1175,17 @@ namespace llvm {
|
||||
/// return true. For pointer types, this is the pointer-sized integer type.
|
||||
Type *getEffectiveSCEVType(Type *Ty) const;
|
||||
|
||||
/// Return true if the SCEV is a scAddRecExpr or it contains
|
||||
/// scAddRecExpr. The result will be cached in HasRecMap.
|
||||
///
|
||||
bool containsAddRecurrence(const SCEV *S);
|
||||
|
||||
/// Return the Value set from which the SCEV expr is generated.
|
||||
SetVector<Value *> *getSCEVValues(const SCEV *S);
|
||||
|
||||
/// Erase Value from ValueExprMap and ExprValueMap.
|
||||
void eraseValueFromMap(Value *V);
|
||||
|
||||
/// Return a SCEV expression for the full generality of the specified
|
||||
/// expression.
|
||||
const SCEV *getSCEV(Value *V);
|
||||
@ -867,7 +1232,7 @@ namespace llvm {
|
||||
SmallVector<const SCEV *, 4> NewOp(Operands.begin(), Operands.end());
|
||||
return getAddRecExpr(NewOp, L, Flags);
|
||||
}
|
||||
/// \brief Returns an expression for a GEP
|
||||
/// Returns an expression for a GEP
|
||||
///
|
||||
/// \p PointeeType The type used as the basis for the pointer arithmetics
|
||||
/// \p BaseExpr The expression for the pointer operand.
|
||||
@ -885,10 +1250,10 @@ namespace llvm {
|
||||
const SCEV *getUnknown(Value *V);
|
||||
const SCEV *getCouldNotCompute();
|
||||
|
||||
/// \brief Return a SCEV for the constant 0 of a specific type.
|
||||
/// Return a SCEV for the constant 0 of a specific type.
|
||||
const SCEV *getZero(Type *Ty) { return getConstant(Ty, 0); }
|
||||
|
||||
/// \brief Return a SCEV for the constant 1 of a specific type.
|
||||
/// Return a SCEV for the constant 1 of a specific type.
|
||||
const SCEV *getOne(Type *Ty) { return getConstant(Ty, 1); }
|
||||
|
||||
/// Return an expression for sizeof AllocTy that is type IntTy
|
||||
@ -981,7 +1346,7 @@ namespace llvm {
|
||||
bool isLoopBackedgeGuardedByCond(const Loop *L, ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS);
|
||||
|
||||
/// \brief Returns the maximum trip count of the loop if it is a single-exit
|
||||
/// Returns the maximum trip count of the loop if it is a single-exit
|
||||
/// loop and we can compute a small maximum for that loop.
|
||||
///
|
||||
/// Implemented in terms of the \c getSmallConstantTripCount overload with
|
||||
@ -997,7 +1362,7 @@ namespace llvm {
|
||||
/// prematurely via another branch.
|
||||
unsigned getSmallConstantTripCount(Loop *L, BasicBlock *ExitingBlock);
|
||||
|
||||
/// \brief Returns the largest constant divisor of the trip count of the
|
||||
/// Returns the largest constant divisor of the trip count of the
|
||||
/// loop if it is a single-exit loop and we can compute a small maximum for
|
||||
/// that loop.
|
||||
///
|
||||
@ -1031,6 +1396,13 @@ namespace llvm {
|
||||
///
|
||||
const SCEV *getBackedgeTakenCount(const Loop *L);
|
||||
|
||||
/// Similar to getBackedgeTakenCount, except it will add a set of
|
||||
/// SCEV predicates to Predicates that are required to be true in order for
|
||||
/// the answer to be correct. Predicates can be checked with run-time
|
||||
/// checks and can be used to perform loop versioning.
|
||||
const SCEV *getPredicatedBackedgeTakenCount(const Loop *L,
|
||||
SCEVUnionPredicate &Predicates);
|
||||
|
||||
/// Similar to getBackedgeTakenCount, except return the least SCEV value
|
||||
/// that is known never to be less than the actual backedge taken count.
|
||||
const SCEV *getMaxBackedgeTakenCount(const Loop *L);
|
||||
@ -1050,7 +1422,7 @@ namespace llvm {
|
||||
/// def-use chain linking it to a loop.
|
||||
void forgetValue(Value *V);
|
||||
|
||||
/// \brief Called when the client has changed the disposition of values in
|
||||
/// Called when the client has changed the disposition of values in
|
||||
/// this loop.
|
||||
///
|
||||
/// We don't have a way to invalidate per-loop dispositions. Clear and
|
||||
@ -1154,7 +1526,8 @@ namespace llvm {
|
||||
const SCEV *getElementSize(Instruction *Inst);
|
||||
|
||||
/// Compute the array dimensions Sizes from the set of Terms extracted from
|
||||
/// the memory access function of this SCEVAddRecExpr.
|
||||
/// the memory access function of this SCEVAddRecExpr (second step of
|
||||
/// delinearization).
|
||||
void findArrayDimensions(SmallVectorImpl<const SCEV *> &Terms,
|
||||
SmallVectorImpl<const SCEV *> &Sizes,
|
||||
const SCEV *ElementSize) const;
|
||||
@ -1162,13 +1535,15 @@ namespace llvm {
|
||||
void print(raw_ostream &OS) const;
|
||||
void verify() const;
|
||||
|
||||
/// Collect parametric terms occurring in step expressions.
|
||||
/// Collect parametric terms occurring in step expressions (first step of
|
||||
/// delinearization).
|
||||
void collectParametricTerms(const SCEV *Expr,
|
||||
SmallVectorImpl<const SCEV *> &Terms);
|
||||
|
||||
|
||||
|
||||
/// Return in Subscripts the access functions for each dimension in Sizes.
|
||||
/// Return in Subscripts the access functions for each dimension in Sizes
|
||||
/// (third step of delinearization).
|
||||
void computeAccessFunctions(const SCEV *Expr,
|
||||
SmallVectorImpl<const SCEV *> &Subscripts,
|
||||
SmallVectorImpl<const SCEV *> &Sizes);
|
||||
@ -1251,8 +1626,18 @@ namespace llvm {
|
||||
const SCEVPredicate *getEqualPredicate(const SCEVUnknown *LHS,
|
||||
const SCEVConstant *RHS);
|
||||
|
||||
/// Re-writes the SCEV according to the Predicates in \p Preds.
|
||||
const SCEV *rewriteUsingPredicate(const SCEV *Scev, SCEVUnionPredicate &A);
|
||||
const SCEVPredicate *
|
||||
getWrapPredicate(const SCEVAddRecExpr *AR,
|
||||
SCEVWrapPredicate::IncrementWrapFlags AddedFlags);
|
||||
|
||||
/// Re-writes the SCEV according to the Predicates in \p A.
|
||||
const SCEV *rewriteUsingPredicate(const SCEV *S, const Loop *L,
|
||||
SCEVUnionPredicate &A);
|
||||
/// Tries to convert the \p S expression to an AddRec expression,
|
||||
/// adding additional predicates to \p Preds as required.
|
||||
const SCEVAddRecExpr *
|
||||
convertSCEVToAddRecWithPredicates(const SCEV *S, const Loop *L,
|
||||
SCEVUnionPredicate &Preds);
|
||||
|
||||
private:
|
||||
/// Compute the backedge taken count knowing the interval difference, the
|
||||
@ -1283,31 +1668,26 @@ namespace llvm {
|
||||
SCEVUnknown *FirstUnknown;
|
||||
};
|
||||
|
||||
/// \brief Analysis pass that exposes the \c ScalarEvolution for a function.
|
||||
class ScalarEvolutionAnalysis {
|
||||
/// Analysis pass that exposes the \c ScalarEvolution for a function.
|
||||
class ScalarEvolutionAnalysis
|
||||
: public AnalysisInfoMixin<ScalarEvolutionAnalysis> {
|
||||
friend AnalysisInfoMixin<ScalarEvolutionAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef ScalarEvolution Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Provide a name for the analysis for debugging and logging.
|
||||
static StringRef name() { return "ScalarEvolutionAnalysis"; }
|
||||
|
||||
ScalarEvolution run(Function &F, AnalysisManager<Function> *AM);
|
||||
ScalarEvolution run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c ScalarEvolutionAnalysis results.
|
||||
class ScalarEvolutionPrinterPass {
|
||||
/// Printer pass for the \c ScalarEvolutionAnalysis results.
|
||||
class ScalarEvolutionPrinterPass
|
||||
: public PassInfoMixin<ScalarEvolutionPrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit ScalarEvolutionPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
static StringRef name() { return "ScalarEvolutionPrinterPass"; }
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
class ScalarEvolutionWrapperPass : public FunctionPass {
|
||||
@ -1343,42 +1723,81 @@ namespace llvm {
|
||||
/// - lowers the number of expression rewrites.
|
||||
class PredicatedScalarEvolution {
|
||||
public:
|
||||
PredicatedScalarEvolution(ScalarEvolution &SE);
|
||||
PredicatedScalarEvolution(ScalarEvolution &SE, Loop &L);
|
||||
const SCEVUnionPredicate &getUnionPredicate() const;
|
||||
/// \brief Returns the SCEV expression of V, in the context of the current
|
||||
/// SCEV predicate.
|
||||
/// The order of transformations applied on the expression of V returned
|
||||
/// by ScalarEvolution is guaranteed to be preserved, even when adding new
|
||||
/// predicates.
|
||||
|
||||
/// Returns the SCEV expression of V, in the context of the current SCEV
|
||||
/// predicate. The order of transformations applied on the expression of V
|
||||
/// returned by ScalarEvolution is guaranteed to be preserved, even when
|
||||
/// adding new predicates.
|
||||
const SCEV *getSCEV(Value *V);
|
||||
/// \brief Adds a new predicate.
|
||||
|
||||
/// Get the (predicated) backedge count for the analyzed loop.
|
||||
const SCEV *getBackedgeTakenCount();
|
||||
|
||||
/// Adds a new predicate.
|
||||
void addPredicate(const SCEVPredicate &Pred);
|
||||
/// \brief Returns the ScalarEvolution analysis used.
|
||||
|
||||
/// Attempts to produce an AddRecExpr for V by adding additional SCEV
|
||||
/// predicates. If we can't transform the expression into an AddRecExpr we
|
||||
/// return nullptr and not add additional SCEV predicates to the current
|
||||
/// context.
|
||||
const SCEVAddRecExpr *getAsAddRec(Value *V);
|
||||
|
||||
/// Proves that V doesn't overflow by adding SCEV predicate.
|
||||
void setNoOverflow(Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags);
|
||||
|
||||
/// Returns true if we've proved that V doesn't wrap by means of a SCEV
|
||||
/// predicate.
|
||||
bool hasNoOverflow(Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags);
|
||||
|
||||
/// Returns the ScalarEvolution analysis used.
|
||||
ScalarEvolution *getSE() const { return &SE; }
|
||||
|
||||
/// We need to explicitly define the copy constructor because of FlagsMap.
|
||||
PredicatedScalarEvolution(const PredicatedScalarEvolution&);
|
||||
|
||||
/// Print the SCEV mappings done by the Predicated Scalar Evolution.
|
||||
/// The printed text is indented by \p Depth.
|
||||
void print(raw_ostream &OS, unsigned Depth) const;
|
||||
|
||||
private:
|
||||
/// \brief Increments the version number of the predicate.
|
||||
/// This needs to be called every time the SCEV predicate changes.
|
||||
/// Increments the version number of the predicate. This needs to be called
|
||||
/// every time the SCEV predicate changes.
|
||||
void updateGeneration();
|
||||
|
||||
/// Holds a SCEV and the version number of the SCEV predicate used to
|
||||
/// perform the rewrite of the expression.
|
||||
typedef std::pair<unsigned, const SCEV *> RewriteEntry;
|
||||
|
||||
/// Maps a SCEV to the rewrite result of that SCEV at a certain version
|
||||
/// number. If this number doesn't match the current Generation, we will
|
||||
/// need to do a rewrite. To preserve the transformation order of previous
|
||||
/// rewrites, we will rewrite the previous result instead of the original
|
||||
/// SCEV.
|
||||
DenseMap<const SCEV *, RewriteEntry> RewriteMap;
|
||||
|
||||
/// Records what NoWrap flags we've added to a Value *.
|
||||
ValueMap<Value *, SCEVWrapPredicate::IncrementWrapFlags> FlagsMap;
|
||||
|
||||
/// The ScalarEvolution analysis.
|
||||
ScalarEvolution &SE;
|
||||
|
||||
/// The analyzed Loop.
|
||||
const Loop &L;
|
||||
|
||||
/// The SCEVPredicate that forms our context. We will rewrite all
|
||||
/// expressions assuming that this predicate true.
|
||||
SCEVUnionPredicate Preds;
|
||||
|
||||
/// Marks the version of the SCEV predicate used. When rewriting a SCEV
|
||||
/// expression we mark it with the version of the predicate. We use this to
|
||||
/// figure out if the predicate has changed from the last rewrite of the
|
||||
/// SCEV. If so, we need to perform a new rewrite.
|
||||
unsigned Generation;
|
||||
|
||||
/// The backedge taken count.
|
||||
const SCEV *BackedgeCount;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,7 @@ class SCEVAAResult : public AAResultBase<SCEVAAResult> {
|
||||
ScalarEvolution &SE;
|
||||
|
||||
public:
|
||||
explicit SCEVAAResult(const TargetLibraryInfo &TLI, ScalarEvolution &SE)
|
||||
: AAResultBase(TLI), SE(SE) {}
|
||||
explicit SCEVAAResult(ScalarEvolution &SE) : AAResultBase(), SE(SE) {}
|
||||
SCEVAAResult(SCEVAAResult &&Arg) : AAResultBase(std::move(Arg)), SE(Arg.SE) {}
|
||||
|
||||
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
|
||||
@ -39,20 +38,14 @@ private:
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
class SCEVAA {
|
||||
class SCEVAA : public AnalysisInfoMixin<SCEVAA> {
|
||||
friend AnalysisInfoMixin<SCEVAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef SCEVAAResult Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
SCEVAAResult run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "SCEVAA"; }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
SCEVAAResult run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the SCEVAAResult object.
|
||||
|
@ -80,9 +80,49 @@ namespace llvm {
|
||||
/// already in "expanded" form.
|
||||
bool LSRMode;
|
||||
|
||||
typedef IRBuilder<true, TargetFolder> BuilderType;
|
||||
typedef IRBuilder<TargetFolder> BuilderType;
|
||||
BuilderType Builder;
|
||||
|
||||
// RAII object that stores the current insertion point and restores it when
|
||||
// the object is destroyed. This includes the debug location. Duplicated
|
||||
// from InsertPointGuard to add SetInsertPoint() which is used to updated
|
||||
// InsertPointGuards stack when insert points are moved during SCEV
|
||||
// expansion.
|
||||
class SCEVInsertPointGuard {
|
||||
IRBuilderBase &Builder;
|
||||
AssertingVH<BasicBlock> Block;
|
||||
BasicBlock::iterator Point;
|
||||
DebugLoc DbgLoc;
|
||||
SCEVExpander *SE;
|
||||
|
||||
SCEVInsertPointGuard(const SCEVInsertPointGuard &) = delete;
|
||||
SCEVInsertPointGuard &operator=(const SCEVInsertPointGuard &) = delete;
|
||||
|
||||
public:
|
||||
SCEVInsertPointGuard(IRBuilderBase &B, SCEVExpander *SE)
|
||||
: Builder(B), Block(B.GetInsertBlock()), Point(B.GetInsertPoint()),
|
||||
DbgLoc(B.getCurrentDebugLocation()), SE(SE) {
|
||||
SE->InsertPointGuards.push_back(this);
|
||||
}
|
||||
|
||||
~SCEVInsertPointGuard() {
|
||||
// These guards should always created/destroyed in FIFO order since they
|
||||
// are used to guard lexically scoped blocks of code in
|
||||
// ScalarEvolutionExpander.
|
||||
assert(SE->InsertPointGuards.back() == this);
|
||||
SE->InsertPointGuards.pop_back();
|
||||
Builder.restoreIP(IRBuilderBase::InsertPoint(Block, Point));
|
||||
Builder.SetCurrentDebugLocation(DbgLoc);
|
||||
}
|
||||
|
||||
BasicBlock::iterator GetInsertPoint() const { return Point; }
|
||||
void SetInsertPoint(BasicBlock::iterator I) { Point = I; }
|
||||
};
|
||||
|
||||
/// Stack of pointers to saved insert points, used to keep insert points
|
||||
/// consistent when instructions are moved.
|
||||
SmallVector<SCEVInsertPointGuard *, 8> InsertPointGuards;
|
||||
|
||||
#ifndef NDEBUG
|
||||
const char *DebugType;
|
||||
#endif
|
||||
@ -101,6 +141,11 @@ namespace llvm {
|
||||
#endif
|
||||
}
|
||||
|
||||
~SCEVExpander() {
|
||||
// Make sure the insert point guard stack is consistent.
|
||||
assert(InsertPointGuards.empty());
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void setDebugType(const char* s) { DebugType = s; }
|
||||
#endif
|
||||
@ -162,6 +207,15 @@ namespace llvm {
|
||||
Value *expandEqualPredicate(const SCEVEqualPredicate *Pred,
|
||||
Instruction *Loc);
|
||||
|
||||
/// \brief Generates code that evaluates if the \p AR expression will
|
||||
/// overflow.
|
||||
Value *generateOverflowCheck(const SCEVAddRecExpr *AR, Instruction *Loc,
|
||||
bool Signed);
|
||||
|
||||
/// \brief A specialized variant of expandCodeForPredicate, handling the
|
||||
/// case when we are expanding code for a SCEVWrapPredicate.
|
||||
Value *expandWrapPredicate(const SCEVWrapPredicate *P, Instruction *Loc);
|
||||
|
||||
/// \brief A specialized variant of expandCodeForPredicate, handling the
|
||||
/// case when we are expanding code for a SCEVUnionPredicate.
|
||||
Value *expandUnionPredicate(const SCEVUnionPredicate *Pred,
|
||||
@ -254,6 +308,9 @@ namespace llvm {
|
||||
const SCEV *const *op_end,
|
||||
PointerType *PTy, Type *Ty, Value *V);
|
||||
|
||||
/// \brief Find a previous Value in ExprValueMap for expand.
|
||||
Value *FindValueInExprValueMap(const SCEV *S, const Instruction *InsertPt);
|
||||
|
||||
Value *expand(const SCEV *S);
|
||||
|
||||
/// \brief Insert code to directly compute the specified SCEV expression
|
||||
@ -306,6 +363,11 @@ namespace llvm {
|
||||
bool &InvertStep);
|
||||
Value *expandIVInc(PHINode *PN, Value *StepV, const Loop *L,
|
||||
Type *ExpandTy, Type *IntTy, bool useSubtract);
|
||||
|
||||
void hoistBeforePos(DominatorTree *DT, Instruction *InstToHoist,
|
||||
Instruction *Pos, PHINode *LoopPhi);
|
||||
|
||||
void fixupInsertPoints(Instruction *I);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,7 @@ namespace llvm {
|
||||
scUnknown, scCouldNotCompute
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVConstant - This class represents a constant integer value.
|
||||
///
|
||||
/// This class represents a constant integer value.
|
||||
class SCEVConstant : public SCEV {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -53,9 +51,7 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVCastExpr - This is the base class for unary cast operator classes.
|
||||
///
|
||||
/// This is the base class for unary cast operator classes.
|
||||
class SCEVCastExpr : public SCEV {
|
||||
protected:
|
||||
const SCEV *Op;
|
||||
@ -76,10 +72,8 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVTruncateExpr - This class represents a truncation of an integer value
|
||||
/// to a smaller integer value.
|
||||
///
|
||||
/// This class represents a truncation of an integer value to a
|
||||
/// smaller integer value.
|
||||
class SCEVTruncateExpr : public SCEVCastExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -93,10 +87,8 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVZeroExtendExpr - This class represents a zero extension of a small
|
||||
/// integer value to a larger integer value.
|
||||
///
|
||||
/// This class represents a zero extension of a small integer value
|
||||
/// to a larger integer value.
|
||||
class SCEVZeroExtendExpr : public SCEVCastExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -110,10 +102,8 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVSignExtendExpr - This class represents a sign extension of a small
|
||||
/// integer value to a larger integer value.
|
||||
///
|
||||
/// This class represents a sign extension of a small integer value
|
||||
/// to a larger integer value.
|
||||
class SCEVSignExtendExpr : public SCEVCastExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -128,10 +118,8 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVNAryExpr - This node is a base class providing common
|
||||
/// functionality for n'ary operators.
|
||||
///
|
||||
/// This node is a base class providing common functionality for
|
||||
/// n'ary operators.
|
||||
class SCEVNAryExpr : public SCEV {
|
||||
protected:
|
||||
// Since SCEVs are immutable, ScalarEvolution allocates operand
|
||||
@ -166,6 +154,18 @@ namespace llvm {
|
||||
return (NoWrapFlags)(SubclassData & Mask);
|
||||
}
|
||||
|
||||
bool hasNoUnsignedWrap() const {
|
||||
return getNoWrapFlags(FlagNUW) != FlagAnyWrap;
|
||||
}
|
||||
|
||||
bool hasNoSignedWrap() const {
|
||||
return getNoWrapFlags(FlagNSW) != FlagAnyWrap;
|
||||
}
|
||||
|
||||
bool hasNoSelfWrap() const {
|
||||
return getNoWrapFlags(FlagNW) != FlagAnyWrap;
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scAddExpr ||
|
||||
@ -176,10 +176,7 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVCommutativeExpr - This node is the base class for n'ary commutative
|
||||
/// operators.
|
||||
///
|
||||
/// This node is the base class for n'ary commutative operators.
|
||||
class SCEVCommutativeExpr : public SCEVNAryExpr {
|
||||
protected:
|
||||
SCEVCommutativeExpr(const FoldingSetNodeIDRef ID,
|
||||
@ -202,9 +199,7 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVAddExpr - This node represents an addition of some number of SCEVs.
|
||||
///
|
||||
/// This node represents an addition of some number of SCEVs.
|
||||
class SCEVAddExpr : public SCEVCommutativeExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -227,9 +222,8 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVMulExpr - This node represents multiplication of some number of SCEVs.
|
||||
///
|
||||
|
||||
/// This node represents multiplication of some number of SCEVs.
|
||||
class SCEVMulExpr : public SCEVCommutativeExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -246,9 +240,7 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVUDivExpr - This class represents a binary unsigned division operation.
|
||||
///
|
||||
/// This class represents a binary unsigned division operation.
|
||||
class SCEVUDivExpr : public SCEV {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -277,12 +269,11 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVAddRecExpr - This node represents a polynomial recurrence on the trip
|
||||
/// count of the specified loop. This is the primary focus of the
|
||||
/// ScalarEvolution framework; all the other SCEV subclasses are mostly just
|
||||
/// supporting infrastructure to allow SCEVAddRecExpr expressions to be
|
||||
/// created and analyzed.
|
||||
/// This node represents a polynomial recurrence on the trip count
|
||||
/// of the specified loop. This is the primary focus of the
|
||||
/// ScalarEvolution framework; all the other SCEV subclasses are
|
||||
/// mostly just supporting infrastructure to allow SCEVAddRecExpr
|
||||
/// expressions to be created and analyzed.
|
||||
///
|
||||
/// All operands of an AddRec are required to be loop invariant.
|
||||
///
|
||||
@ -299,10 +290,10 @@ namespace llvm {
|
||||
const SCEV *getStart() const { return Operands[0]; }
|
||||
const Loop *getLoop() const { return L; }
|
||||
|
||||
/// getStepRecurrence - This method constructs and returns the recurrence
|
||||
/// indicating how much this expression steps by. If this is a polynomial
|
||||
/// of degree N, it returns a chrec of degree N-1.
|
||||
/// We cannot determine whether the step recurrence has self-wraparound.
|
||||
/// Constructs and returns the recurrence indicating how much this
|
||||
/// expression steps by. If this is a polynomial of degree N, it
|
||||
/// returns a chrec of degree N-1. We cannot determine whether
|
||||
/// the step recurrence has self-wraparound.
|
||||
const SCEV *getStepRecurrence(ScalarEvolution &SE) const {
|
||||
if (isAffine()) return getOperand(1);
|
||||
return SE.getAddRecExpr(SmallVector<const SCEV *, 3>(op_begin()+1,
|
||||
@ -310,17 +301,17 @@ namespace llvm {
|
||||
getLoop(), FlagAnyWrap);
|
||||
}
|
||||
|
||||
/// isAffine - Return true if this represents an expression
|
||||
/// A + B*x where A and B are loop invariant values.
|
||||
/// Return true if this represents an expression A + B*x where A
|
||||
/// and B are loop invariant values.
|
||||
bool isAffine() const {
|
||||
// We know that the start value is invariant. This expression is thus
|
||||
// affine iff the step is also invariant.
|
||||
return getNumOperands() == 2;
|
||||
}
|
||||
|
||||
/// isQuadratic - Return true if this represents an expression
|
||||
/// A + B*x + C*x^2 where A, B and C are loop invariant values.
|
||||
/// This corresponds to an addrec of the form {L,+,M,+,N}
|
||||
/// Return true if this represents an expression A + B*x + C*x^2
|
||||
/// where A, B and C are loop invariant values. This corresponds
|
||||
/// to an addrec of the form {L,+,M,+,N}
|
||||
bool isQuadratic() const {
|
||||
return getNumOperands() == 3;
|
||||
}
|
||||
@ -334,21 +325,21 @@ namespace llvm {
|
||||
SubclassData |= Flags;
|
||||
}
|
||||
|
||||
/// evaluateAtIteration - Return the value of this chain of recurrences at
|
||||
/// the specified iteration number.
|
||||
/// Return the value of this chain of recurrences at the specified
|
||||
/// iteration number.
|
||||
const SCEV *evaluateAtIteration(const SCEV *It, ScalarEvolution &SE) const;
|
||||
|
||||
/// getNumIterationsInRange - Return the number of iterations of this loop
|
||||
/// that produce values in the specified constant range. Another way of
|
||||
/// looking at this is that it returns the first iteration number where the
|
||||
/// value is not in the condition, thus computing the exit count. If the
|
||||
/// iteration count can't be computed, an instance of SCEVCouldNotCompute is
|
||||
/// returned.
|
||||
const SCEV *getNumIterationsInRange(ConstantRange Range,
|
||||
ScalarEvolution &SE) const;
|
||||
/// Return the number of iterations of this loop that produce
|
||||
/// values in the specified constant range. Another way of
|
||||
/// looking at this is that it returns the first iteration number
|
||||
/// where the value is not in the condition, thus computing the
|
||||
/// exit count. If the iteration count can't be computed, an
|
||||
/// instance of SCEVCouldNotCompute is returned.
|
||||
const SCEV *getNumIterationsInRange(const ConstantRange &Range,
|
||||
ScalarEvolution &SE) const;
|
||||
|
||||
/// getPostIncExpr - Return an expression representing the value of
|
||||
/// this expression one iteration of the loop ahead.
|
||||
/// Return an expression representing the value of this expression
|
||||
/// one iteration of the loop ahead.
|
||||
const SCEVAddRecExpr *getPostIncExpr(ScalarEvolution &SE) const {
|
||||
return cast<SCEVAddRecExpr>(SE.getAddExpr(this, getStepRecurrence(SE)));
|
||||
}
|
||||
@ -359,9 +350,7 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVSMaxExpr - This class represents a signed maximum selection.
|
||||
///
|
||||
/// This class represents a signed maximum selection.
|
||||
class SCEVSMaxExpr : public SCEVCommutativeExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -380,9 +369,7 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVUMaxExpr - This class represents an unsigned maximum selection.
|
||||
///
|
||||
/// This class represents an unsigned maximum selection.
|
||||
class SCEVUMaxExpr : public SCEVCommutativeExpr {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -400,11 +387,9 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// SCEVUnknown - This means that we are dealing with an entirely unknown SCEV
|
||||
/// value, and only represent it as its LLVM Value. This is the "bottom"
|
||||
/// value for the analysis.
|
||||
///
|
||||
/// This means that we are dealing with an entirely unknown SCEV
|
||||
/// value, and only represent it as its LLVM Value. This is the
|
||||
/// "bottom" value for the analysis.
|
||||
class SCEVUnknown final : public SCEV, private CallbackVH {
|
||||
friend class ScalarEvolution;
|
||||
|
||||
@ -412,13 +397,13 @@ namespace llvm {
|
||||
void deleted() override;
|
||||
void allUsesReplacedWith(Value *New) override;
|
||||
|
||||
/// SE - The parent ScalarEvolution value. This is used to update
|
||||
/// the parent's maps when the value associated with a SCEVUnknown
|
||||
/// is deleted or RAUW'd.
|
||||
/// The parent ScalarEvolution value. This is used to update the
|
||||
/// parent's maps when the value associated with a SCEVUnknown is
|
||||
/// deleted or RAUW'd.
|
||||
ScalarEvolution *SE;
|
||||
|
||||
/// Next - The next pointer in the linked list of all
|
||||
/// SCEVUnknown instances owned by a ScalarEvolution.
|
||||
/// The next pointer in the linked list of all SCEVUnknown
|
||||
/// instances owned by a ScalarEvolution.
|
||||
SCEVUnknown *Next;
|
||||
|
||||
SCEVUnknown(const FoldingSetNodeIDRef ID, Value *V,
|
||||
@ -428,15 +413,17 @@ namespace llvm {
|
||||
public:
|
||||
Value *getValue() const { return getValPtr(); }
|
||||
|
||||
/// isSizeOf, isAlignOf, isOffsetOf - Test whether this is a special
|
||||
/// constant representing a type size, alignment, or field offset in
|
||||
/// a target-independent manner, and hasn't happened to have been
|
||||
/// folded with other operations into something unrecognizable. This
|
||||
/// is mainly only useful for pretty-printing and other situations
|
||||
/// where it isn't absolutely required for these to succeed.
|
||||
/// @{
|
||||
/// Test whether this is a special constant representing a type
|
||||
/// size, alignment, or field offset in a target-independent
|
||||
/// manner, and hasn't happened to have been folded with other
|
||||
/// operations into something unrecognizable. This is mainly only
|
||||
/// useful for pretty-printing and other situations where it isn't
|
||||
/// absolutely required for these to succeed.
|
||||
bool isSizeOf(Type *&AllocTy) const;
|
||||
bool isAlignOf(Type *&AllocTy) const;
|
||||
bool isOffsetOf(Type *&STy, Constant *&FieldNo) const;
|
||||
/// @}
|
||||
|
||||
Type *getType() const { return getValPtr()->getType(); }
|
||||
|
||||
@ -446,8 +433,8 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
/// SCEVVisitor - This class defines a simple visitor class that may be used
|
||||
/// for various SCEV analysis purposes.
|
||||
/// This class defines a simple visitor class that may be used for
|
||||
/// various SCEV analysis purposes.
|
||||
template<typename SC, typename RetVal=void>
|
||||
struct SCEVVisitor {
|
||||
RetVal visit(const SCEV *S) {
|
||||
@ -524,14 +511,10 @@ namespace llvm {
|
||||
case scMulExpr:
|
||||
case scSMaxExpr:
|
||||
case scUMaxExpr:
|
||||
case scAddRecExpr: {
|
||||
const SCEVNAryExpr *NAry = cast<SCEVNAryExpr>(S);
|
||||
for (SCEVNAryExpr::op_iterator I = NAry->op_begin(),
|
||||
E = NAry->op_end(); I != E; ++I) {
|
||||
push(*I);
|
||||
}
|
||||
case scAddRecExpr:
|
||||
for (const auto *Op : cast<SCEVNAryExpr>(S)->operands())
|
||||
push(Op);
|
||||
break;
|
||||
}
|
||||
case scUDivExpr: {
|
||||
const SCEVUDivExpr *UDiv = cast<SCEVUDivExpr>(S);
|
||||
push(UDiv->getLHS());
|
||||
@ -697,13 +680,6 @@ namespace llvm {
|
||||
private:
|
||||
LoopToScevMapT ⤅
|
||||
};
|
||||
|
||||
/// Applies the Map (Loop -> SCEV) to the given Scev.
|
||||
static inline const SCEV *apply(const SCEV *Scev, LoopToScevMapT &Map,
|
||||
ScalarEvolution &SE) {
|
||||
return SCEVLoopAddRecRewriter::rewrite(Scev, Map, SE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -27,8 +27,7 @@ class ScopedNoAliasAAResult : public AAResultBase<ScopedNoAliasAAResult> {
|
||||
friend AAResultBase<ScopedNoAliasAAResult>;
|
||||
|
||||
public:
|
||||
explicit ScopedNoAliasAAResult(const TargetLibraryInfo &TLI)
|
||||
: AAResultBase(TLI) {}
|
||||
explicit ScopedNoAliasAAResult() : AAResultBase() {}
|
||||
ScopedNoAliasAAResult(ScopedNoAliasAAResult &&Arg)
|
||||
: AAResultBase(std::move(Arg)) {}
|
||||
|
||||
@ -48,20 +47,14 @@ private:
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
class ScopedNoAliasAA {
|
||||
class ScopedNoAliasAA : public AnalysisInfoMixin<ScopedNoAliasAA> {
|
||||
friend AnalysisInfoMixin<ScopedNoAliasAA>;
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef ScopedNoAliasAAResult Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
ScopedNoAliasAAResult run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "ScopedNoAliasAA"; }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
ScopedNoAliasAAResult run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
|
||||
/// Legacy wrapper pass to provide the ScopedNoAliasAAResult object.
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
|
@ -195,6 +195,11 @@ TLI_DEFINE_STRING_INTERNAL("__memmove_chk")
|
||||
/// void *__memset_chk(void *s, char v, size_t n, size_t s1size);
|
||||
TLI_DEFINE_ENUM_INTERNAL(memset_chk)
|
||||
TLI_DEFINE_STRING_INTERNAL("__memset_chk")
|
||||
|
||||
// int __nvvm_reflect(const char *)
|
||||
TLI_DEFINE_ENUM_INTERNAL(nvvm_reflect)
|
||||
TLI_DEFINE_STRING_INTERNAL("__nvvm_reflect")
|
||||
|
||||
/// double __sincospi_stret(double x);
|
||||
TLI_DEFINE_ENUM_INTERNAL(sincospi_stret)
|
||||
TLI_DEFINE_STRING_INTERNAL("__sincospi_stret")
|
||||
|
@ -11,15 +11,17 @@
|
||||
#define LLVM_ANALYSIS_TARGETLIBRARYINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
/// VecDesc - Describes a possible vectorization of a function.
|
||||
template <typename T> class ArrayRef;
|
||||
|
||||
/// Describes a possible vectorization of a function.
|
||||
/// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized
|
||||
/// by a factor 'VectorizationFactor'.
|
||||
struct VecDesc {
|
||||
@ -27,7 +29,6 @@ struct VecDesc {
|
||||
const char *VectorFnName;
|
||||
unsigned VectorizationFactor;
|
||||
};
|
||||
class PreservedAnalyses;
|
||||
|
||||
namespace LibFunc {
|
||||
enum Func {
|
||||
@ -38,7 +39,7 @@ class PreservedAnalyses;
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Implementation of the target library information.
|
||||
/// Implementation of the target library information.
|
||||
///
|
||||
/// This class constructs tables that hold the target library information and
|
||||
/// make it available. However, it is somewhat expensive to compute and only
|
||||
@ -70,8 +71,13 @@ class TargetLibraryInfoImpl {
|
||||
/// on VectorFnName rather than ScalarFnName.
|
||||
std::vector<VecDesc> ScalarDescs;
|
||||
|
||||
/// Return true if the function type FTy is valid for the library function
|
||||
/// F, regardless of whether the function is available.
|
||||
bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc::Func F,
|
||||
const DataLayout *DL) const;
|
||||
|
||||
public:
|
||||
/// \brief List of known vector-functions libraries.
|
||||
/// List of known vector-functions libraries.
|
||||
///
|
||||
/// The vector-functions library defines, which functions are vectorizable
|
||||
/// and with which factor. The library can be specified by either frontend,
|
||||
@ -92,24 +98,31 @@ public:
|
||||
TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI);
|
||||
TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI);
|
||||
|
||||
/// \brief Searches for a particular function name.
|
||||
/// Searches for a particular function name.
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(StringRef funcName, LibFunc::Func &F) const;
|
||||
|
||||
/// \brief Forces a function to be marked as unavailable.
|
||||
/// Searches for a particular function name, also checking that its type is
|
||||
/// valid for the library function matching that name.
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const;
|
||||
|
||||
/// Forces a function to be marked as unavailable.
|
||||
void setUnavailable(LibFunc::Func F) {
|
||||
setState(F, Unavailable);
|
||||
}
|
||||
|
||||
/// \brief Forces a function to be marked as available.
|
||||
/// Forces a function to be marked as available.
|
||||
void setAvailable(LibFunc::Func F) {
|
||||
setState(F, StandardName);
|
||||
}
|
||||
|
||||
/// \brief Forces a function to be marked as available and provide an
|
||||
/// alternate name that must be used.
|
||||
/// Forces a function to be marked as available and provide an alternate name
|
||||
/// that must be used.
|
||||
void setAvailableWithName(LibFunc::Func F, StringRef Name) {
|
||||
if (StandardNames[F] != Name) {
|
||||
setState(F, CustomName);
|
||||
@ -120,48 +133,47 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Disables all builtins.
|
||||
/// Disables all builtins.
|
||||
///
|
||||
/// This can be used for options like -fno-builtin.
|
||||
void disableAllFunctions();
|
||||
|
||||
/// addVectorizableFunctions - Add a set of scalar -> vector mappings,
|
||||
/// queryable via getVectorizedFunction and getScalarizedFunction.
|
||||
/// Add a set of scalar -> vector mappings, queryable via
|
||||
/// getVectorizedFunction and getScalarizedFunction.
|
||||
void addVectorizableFunctions(ArrayRef<VecDesc> Fns);
|
||||
|
||||
/// Calls addVectorizableFunctions with a known preset of functions for the
|
||||
/// given vector library.
|
||||
void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib);
|
||||
|
||||
/// isFunctionVectorizable - Return true if the function F has a
|
||||
/// vector equivalent with vectorization factor VF.
|
||||
/// Return true if the function F has a vector equivalent with vectorization
|
||||
/// factor VF.
|
||||
bool isFunctionVectorizable(StringRef F, unsigned VF) const {
|
||||
return !getVectorizedFunction(F, VF).empty();
|
||||
}
|
||||
|
||||
/// isFunctionVectorizable - Return true if the function F has a
|
||||
/// vector equivalent with any vectorization factor.
|
||||
/// Return true if the function F has a vector equivalent with any
|
||||
/// vectorization factor.
|
||||
bool isFunctionVectorizable(StringRef F) const;
|
||||
|
||||
/// getVectorizedFunction - Return the name of the equivalent of
|
||||
/// F, vectorized with factor VF. If no such mapping exists,
|
||||
/// return the empty string.
|
||||
/// Return the name of the equivalent of F, vectorized with factor VF. If no
|
||||
/// such mapping exists, return the empty string.
|
||||
StringRef getVectorizedFunction(StringRef F, unsigned VF) const;
|
||||
|
||||
/// isFunctionScalarizable - Return true if the function F has a
|
||||
/// scalar equivalent, and set VF to be the vectorization factor.
|
||||
/// Return true if the function F has a scalar equivalent, and set VF to be
|
||||
/// the vectorization factor.
|
||||
bool isFunctionScalarizable(StringRef F, unsigned &VF) const {
|
||||
return !getScalarizedFunction(F, VF).empty();
|
||||
}
|
||||
|
||||
/// getScalarizedFunction - Return the name of the equivalent of
|
||||
/// F, scalarized. If no such mapping exists, return the empty string.
|
||||
/// Return the name of the equivalent of F, scalarized. If no such mapping
|
||||
/// exists, return the empty string.
|
||||
///
|
||||
/// Set VF to the vectorization factor.
|
||||
StringRef getScalarizedFunction(StringRef F, unsigned &VF) const;
|
||||
};
|
||||
|
||||
/// \brief Provides information about what library functions are available for
|
||||
/// Provides information about what library functions are available for
|
||||
/// the current target.
|
||||
///
|
||||
/// This both allows optimizations to handle them specially and frontends to
|
||||
@ -187,7 +199,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Searches for a particular function name.
|
||||
/// Searches for a particular function name.
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
@ -195,7 +207,11 @@ public:
|
||||
return Impl->getLibFunc(funcName, F);
|
||||
}
|
||||
|
||||
/// \brief Tests whether a library function is available.
|
||||
bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const {
|
||||
return Impl->getLibFunc(FDecl, F);
|
||||
}
|
||||
|
||||
/// Tests whether a library function is available.
|
||||
bool has(LibFunc::Func F) const {
|
||||
return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable;
|
||||
}
|
||||
@ -209,8 +225,8 @@ public:
|
||||
return Impl->getVectorizedFunction(F, VF);
|
||||
}
|
||||
|
||||
/// \brief Tests if the function is both available and a candidate for
|
||||
/// optimized code generation.
|
||||
/// Tests if the function is both available and a candidate for optimized code
|
||||
/// generation.
|
||||
bool hasOptimizedCodeGen(LibFunc::Func F) const {
|
||||
if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable)
|
||||
return false;
|
||||
@ -251,31 +267,28 @@ public:
|
||||
return Impl->CustomNames.find(F)->second;
|
||||
}
|
||||
|
||||
/// \brief Handle invalidation from the pass manager.
|
||||
/// Handle invalidation from the pass manager.
|
||||
///
|
||||
/// If we try to invalidate this info, just return false. It cannot become
|
||||
/// invalid even if the module changes.
|
||||
bool invalidate(Module &, const PreservedAnalyses &) { return false; }
|
||||
};
|
||||
|
||||
/// \brief Analysis pass providing the \c TargetLibraryInfo.
|
||||
/// Analysis pass providing the \c TargetLibraryInfo.
|
||||
///
|
||||
/// Note that this pass's result cannot be invalidated, it is immutable for the
|
||||
/// life of the module.
|
||||
class TargetLibraryAnalysis {
|
||||
class TargetLibraryAnalysis : public AnalysisInfoMixin<TargetLibraryAnalysis> {
|
||||
public:
|
||||
typedef TargetLibraryInfo Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Default construct the library analysis.
|
||||
/// Default construct the library analysis.
|
||||
///
|
||||
/// This will use the module's triple to construct the library info for that
|
||||
/// module.
|
||||
TargetLibraryAnalysis() {}
|
||||
|
||||
/// \brief Construct a library analysis with preset info.
|
||||
/// Construct a library analysis with preset info.
|
||||
///
|
||||
/// This will directly copy the preset info into the result without
|
||||
/// consulting the module's triple.
|
||||
@ -291,20 +304,18 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
TargetLibraryInfo run(Module &M);
|
||||
TargetLibraryInfo run(Function &F);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "TargetLibraryAnalysis"; }
|
||||
TargetLibraryInfo run(Module &M, ModuleAnalysisManager &);
|
||||
TargetLibraryInfo run(Function &F, FunctionAnalysisManager &);
|
||||
|
||||
private:
|
||||
friend AnalysisInfoMixin<TargetLibraryAnalysis>;
|
||||
static char PassID;
|
||||
|
||||
Optional<TargetLibraryInfoImpl> PresetInfoImpl;
|
||||
|
||||
StringMap<std::unique_ptr<TargetLibraryInfoImpl>> Impls;
|
||||
|
||||
TargetLibraryInfoImpl &lookupInfoImpl(Triple T);
|
||||
TargetLibraryInfoImpl &lookupInfoImpl(const Triple &T);
|
||||
};
|
||||
|
||||
class TargetLibraryInfoWrapperPass : public ImmutablePass {
|
||||
|
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