diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 3c6f394e395d18..4f2c6d46802895 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -469,6 +469,99 @@ CorInfoType Compiler::getBaseJitTypeFromArgIfNeeded(NamedIntrinsic intrins return (diffInsCount >= 2); } +struct IntrinsicKey +{ + CORINFO_InstructionSet Isa; + int NumArgs; + const char* Name; + + IntrinsicKey(CORINFO_InstructionSet isa, int numArgs, const char* name) + : Isa(isa) + , NumArgs(numArgs) + , Name(name) + { + } +}; + +struct IntrinsicKeyFuncs +{ + static bool Equals(const IntrinsicKey& lhs, const IntrinsicKey& rhs) + { + return (lhs.Isa == rhs.Isa) && (lhs.NumArgs == rhs.NumArgs) && (strcmp(lhs.Name, rhs.Name) == 0); + } + + static int GetHashCode(const IntrinsicKey& key) + { + uint32_t hash = static_cast(key.Isa); + hash ^= key.NumArgs + 0x9e3779b9 + (hash << 19) + (hash >> 13); + hash ^= HashStringA(key.Name) + 0x9e3779b9 + (hash << 19) + (hash >> 13); + return static_cast(hash); + } +}; + +struct MallocAllocator +{ + template + T* allocate(size_t count) + { + void* p = malloc(count * sizeof(T)); + if (p == nullptr) + { + NOMEM(); + } + + return static_cast(p); + } + + void deallocate(void* p) + { + free(p); + } +}; + +typedef JitHashTable IntrinsicsHashTable; + +static IntrinsicsHashTable* volatile s_intrinsicsHashTable; + +//------------------------------------------------------------------------ +// getIntrinsicsHashTable: Get the hash table for name -> ID lookups. +// +// Return Value: +// Hash table. +// +static IntrinsicsHashTable* getIntrinsicsHashTable() +{ + if (s_intrinsicsHashTable != nullptr) + { + return s_intrinsicsHashTable; + } + + MallocAllocator mallocator; + char* mem = mallocator.allocate(sizeof(IntrinsicsHashTable)); + + IntrinsicsHashTable* hashTable = new (mem, jitstd::placement_t()) IntrinsicsHashTable(mallocator); + + hashTable->Reallocate(NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START - 1); + + for (int i = 0; i < (NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START - 1); i++) + { + const HWIntrinsicInfo& intrinsicInfo = hwIntrinsicInfoArray[i]; + hashTable->Set(IntrinsicKey(static_cast(intrinsicInfo.isa), intrinsicInfo.numArgs, + intrinsicInfo.name), + intrinsicInfo.id); + } + + IntrinsicsHashTable* observed = InterlockedCompareExchangeT(&s_intrinsicsHashTable, hashTable, nullptr); + if (observed != nullptr) + { + hashTable->~IntrinsicsHashTable(); + mallocator.deallocate(hashTable); + return observed; + } + + return hashTable; +} + //------------------------------------------------------------------------ // lookupId: Gets the NamedIntrinsic for a given method name and InstructionSet // @@ -621,35 +714,20 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, } #endif - for (int i = 0; i < (NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START - 1); i++) + IntrinsicsHashTable* hashTable = getIntrinsicsHashTable(); + NamedIntrinsic ni; + if (hashTable->Lookup(IntrinsicKey(isa, sig->numArgs, methodName), &ni) || + hashTable->Lookup(IntrinsicKey(isa, -1, methodName), &ni)) { - const HWIntrinsicInfo& intrinsicInfo = hwIntrinsicInfoArray[i]; - - if (isa != hwIntrinsicInfoArray[i].isa) - { - continue; - } - - int numArgs = static_cast(intrinsicInfo.numArgs); - - if ((numArgs != -1) && (sig->numArgs != static_cast(intrinsicInfo.numArgs))) +#if defined(TARGET_XARCH) + // on AVX1-only CPUs we only support a subset of intrinsics in Vector256 + if (isLimitedVector256Isa && !AvxOnlyCompatible(ni)) { - continue; + return NI_Illegal; } - - if (strcmp(methodName, intrinsicInfo.name) == 0) - { - NamedIntrinsic ni = intrinsicInfo.id; - -#if defined(TARGET_XARCH) - // on AVX1-only CPUs we only support a subset of intrinsics in Vector256 - if (isLimitedVector256Isa && !AvxOnlyCompatible(ni)) - { - return NI_Illegal; - } #endif - return ni; - } + + return ni; } // There are several helper intrinsics that are implemented in managed code