Cache the result of Function::getIntrinsicID() in a DenseMap attached to the LLVMContext.

This reduces the time actually spent doing string to ID conversion and shows a 10% improvement in compile time for a particularly bad case that involves ARM Neon intrinsics (these have many overloads).

Patch by Jean-Luc Duprat!



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176365 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Ilseman 2013-03-01 18:48:54 +00:00
parent a6b20ced76
commit 4c8e74f0b7
5 changed files with 44 additions and 7 deletions

View File

@ -113,6 +113,10 @@ private:
Function(const Function&) LLVM_DELETED_FUNCTION; Function(const Function&) LLVM_DELETED_FUNCTION;
void operator=(const Function&) LLVM_DELETED_FUNCTION; void operator=(const Function&) LLVM_DELETED_FUNCTION;
/// Do the actual lookup of an intrinsic ID when the query could not be
/// answered from the cache.
unsigned lookupIntrinsicID() const LLVM_READONLY;
/// Function ctor - If the (optional) Module argument is specified, the /// Function ctor - If the (optional) Module argument is specified, the
/// function is automatically inserted into the end of the function list for /// function is automatically inserted into the end of the function list for
/// the module. /// the module.
@ -141,10 +145,12 @@ public:
/// getIntrinsicID - This method returns the ID number of the specified /// getIntrinsicID - This method returns the ID number of the specified
/// function, or Intrinsic::not_intrinsic if the function is not an /// function, or Intrinsic::not_intrinsic if the function is not an
/// instrinsic, or if the pointer is null. This value is always defined to be /// intrinsic, or if the pointer is null. This value is always defined to be
/// zero to allow easy checking for whether a function is intrinsic or not. /// zero to allow easy checking for whether a function is intrinsic or not.
/// The particular intrinsic functions which correspond to this value are /// The particular intrinsic functions which correspond to this value are
/// defined in llvm/Intrinsics.h. /// defined in llvm/Intrinsics.h. Results are cached in the LLVM context,
/// subsequent requests for the same ID return results much faster from the
/// cache.
/// ///
unsigned getIntrinsicID() const LLVM_READONLY; unsigned getIntrinsicID() const LLVM_READONLY;
bool isIntrinsic() const { return getName().startswith("llvm."); } bool isIntrinsic() const { return getName().startswith("llvm."); }

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
#include "LLVMContextImpl.h"
#include "SymbolTableListTraitsImpl.h" #include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
@ -208,6 +209,10 @@ Function::~Function() {
// Remove the function from the on-the-side GC table. // Remove the function from the on-the-side GC table.
clearGC(); clearGC();
// Remove the intrinsicID from the Cache.
if(getValueName() && isIntrinsic())
getContext().pImpl->IntrinsicIDCache.erase(this);
} }
void Function::BuildLazyArguments() const { void Function::BuildLazyArguments() const {
@ -337,18 +342,35 @@ void Function::copyAttributesFrom(const GlobalValue *Src) {
/// intrinsic, or if the pointer is null. This value is always defined to be /// intrinsic, or if the pointer is null. This value is always defined to be
/// zero to allow easy checking for whether a function is intrinsic or not. The /// zero to allow easy checking for whether a function is intrinsic or not. The
/// particular intrinsic functions which correspond to this value are defined in /// particular intrinsic functions which correspond to this value are defined in
/// llvm/Intrinsics.h. /// llvm/Intrinsics.h. Results are cached in the LLVM context, subsequent
/// requests for the same ID return results much faster from the cache.
/// ///
unsigned Function::getIntrinsicID() const { unsigned Function::getIntrinsicID() const {
const ValueName *ValName = this->getValueName(); const ValueName *ValName = this->getValueName();
if (!ValName || !isIntrinsic()) if (!ValName || !isIntrinsic())
return 0; return 0;
LLVMContextImpl::IntrinsicIDCacheTy &IntrinsicIDCache =
getContext().pImpl->IntrinsicIDCache;
if(!IntrinsicIDCache.count(this)) {
unsigned Id = lookupIntrinsicID();
IntrinsicIDCache[this]=Id;
return Id;
}
return IntrinsicIDCache[this];
}
/// This private method does the actual lookup of an intrinsic ID when the query
/// could not be answered from the cache.
unsigned Function::lookupIntrinsicID() const {
const ValueName *ValName = this->getValueName();
unsigned Len = ValName->getKeyLength(); unsigned Len = ValName->getKeyLength();
const char *Name = ValName->getKeyData(); const char *Name = ValName->getKeyData();
#define GET_FUNCTION_RECOGNIZER #define GET_FUNCTION_RECOGNIZER
#include "llvm/IR/Intrinsics.gen" #include "llvm/IR/Intrinsics.gen"
#undef GET_FUNCTION_RECOGNIZER #undef GET_FUNCTION_RECOGNIZER
return 0; return 0;
} }

View File

@ -318,7 +318,7 @@ public:
/// ValueHandles - This map keeps track of all of the value handles that are /// ValueHandles - This map keeps track of all of the value handles that are
/// watching a Value*. The Value::HasValueHandle bit is used to know /// watching a Value*. The Value::HasValueHandle bit is used to know
// whether or not a value has an entry in this map. /// whether or not a value has an entry in this map.
typedef DenseMap<Value*, ValueHandleBase*> ValueHandlesTy; typedef DenseMap<Value*, ValueHandleBase*> ValueHandlesTy;
ValueHandlesTy ValueHandles; ValueHandlesTy ValueHandles;
@ -350,6 +350,11 @@ public:
/// to date. /// to date.
std::vector<std::pair<DebugRecVH, DebugRecVH> > ScopeInlinedAtRecords; std::vector<std::pair<DebugRecVH, DebugRecVH> > ScopeInlinedAtRecords;
/// IntrinsicIDCache - Cache of intrinsic name (string) to numeric ID mappings
/// requested in this context
typedef DenseMap<const Function*, unsigned> IntrinsicIDCacheTy;
IntrinsicIDCacheTy IntrinsicIDCache;
int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx); int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx);
int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx); int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx);

View File

@ -13,6 +13,7 @@
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "SymbolTableListTraitsImpl.h" #include "SymbolTableListTraitsImpl.h"
#include "LLVMContextImpl.h"
#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"

View File

@ -195,6 +195,9 @@ void Value::setName(const Twine &NewName) {
if (getSymTab(this, ST)) if (getSymTab(this, ST))
return; // Cannot set a name on this value (e.g. constant). return; // Cannot set a name on this value (e.g. constant).
if (Function *F = dyn_cast<Function>(this))
getContext().pImpl->IntrinsicIDCache.erase(F);
if (!ST) { // No symbol table to update? Just do the change. if (!ST) { // No symbol table to update? Just do the change.
if (NameRef.empty()) { if (NameRef.empty()) {
// Free the name for this value. // Free the name for this value.
@ -307,7 +310,7 @@ void Value::replaceAllUsesWith(Value *New) {
// Notify all ValueHandles (if present) that this value is going away. // Notify all ValueHandles (if present) that this value is going away.
if (HasValueHandle) if (HasValueHandle)
ValueHandleBase::ValueIsRAUWd(this, New); ValueHandleBase::ValueIsRAUWd(this, New);
while (!use_empty()) { while (!use_empty()) {
Use &U = *UseList; Use &U = *UseList;
// Must handle Constants specially, we cannot call replaceUsesOfWith on a // Must handle Constants specially, we cannot call replaceUsesOfWith on a
@ -318,10 +321,10 @@ void Value::replaceAllUsesWith(Value *New) {
continue; continue;
} }
} }
U.set(New); U.set(New);
} }
if (BasicBlock *BB = dyn_cast<BasicBlock>(this)) if (BasicBlock *BB = dyn_cast<BasicBlock>(this))
BB->replaceSuccessorsPhiUsesWith(cast<BasicBlock>(New)); BB->replaceSuccessorsPhiUsesWith(cast<BasicBlock>(New));
} }