[clang][RISCV][NFC] Prevent data race in RVVType::computeType

Introduce a RVVTypeCache to hold the cache instead of using a local
static variable to maintain a cache.

Also made construct of RVVType to private, make sure that could be only
created by a cache manager.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D138429
This commit is contained in:
Kito Cheng 2022-11-21 22:18:54 +08:00
parent 7fbdee3e29
commit 3fe89be801
4 changed files with 54 additions and 43 deletions

View File

@ -15,7 +15,9 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include <cstdint> #include <cstdint>
#include <set>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
namespace llvm { namespace llvm {
@ -182,9 +184,12 @@ struct LMULType {
class RVVType; class RVVType;
using RVVTypePtr = RVVType *; using RVVTypePtr = RVVType *;
using RVVTypes = std::vector<RVVTypePtr>; using RVVTypes = std::vector<RVVTypePtr>;
class RVVTypeCache;
// This class is compact representation of a valid and invalid RVVType. // This class is compact representation of a valid and invalid RVVType.
class RVVType { class RVVType {
friend class RVVTypeCache;
BasicType BT; BasicType BT;
ScalarTypeKind ScalarType = Invalid; ScalarTypeKind ScalarType = Invalid;
LMULType LMUL; LMULType LMUL;
@ -204,10 +209,9 @@ class RVVType {
enum class FixedLMULType { LargerThan, SmallerThan }; enum class FixedLMULType { LargerThan, SmallerThan };
public:
RVVType() : BT(BasicType::Unknown), LMUL(0), Valid(false) {}
RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile); RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile);
public:
// Return the string representation of a type, which is an encoded string for // Return the string representation of a type, which is an encoded string for
// passing to the BUILTIN() macro in Builtins.def. // passing to the BUILTIN() macro in Builtins.def.
const std::string &getBuiltinStr() const { return BuiltinStr; } const std::string &getBuiltinStr() const { return BuiltinStr; }
@ -275,16 +279,24 @@ private:
void initTypeStr(); void initTypeStr();
// Compute and record a short name of a type for C/C++ name suffix. // Compute and record a short name of a type for C/C++ name suffix.
void initShortStr(); void initShortStr();
};
// This class is used to manage RVVType, RVVType should only created by this
// class, also provided thread-safe cache capability.
class RVVTypeCache {
private:
std::unordered_map<uint64_t, RVVType> LegalTypes;
std::set<uint64_t> IllegalTypes;
public: public:
/// Compute output and input types by applying different config (basic type /// Compute output and input types by applying different config (basic type
/// and LMUL with type transformers). It also record result of type in legal /// and LMUL with type transformers). It also record result of type in legal
/// or illegal set to avoid compute the same config again. The result maybe /// or illegal set to avoid compute the same config again. The result maybe
/// have illegal RVVType. /// have illegal RVVType.
static llvm::Optional<RVVTypes> llvm::Optional<RVVTypes>
computeTypes(BasicType BT, int Log2LMUL, unsigned NF, computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
llvm::ArrayRef<PrototypeDescriptor> Prototype); llvm::ArrayRef<PrototypeDescriptor> Prototype);
static llvm::Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, llvm::Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
PrototypeDescriptor Proto); PrototypeDescriptor Proto);
}; };
@ -373,7 +385,7 @@ public:
std::string getBuiltinTypeStr() const; std::string getBuiltinTypeStr() const;
static std::string static std::string
getSuffixStr(BasicType Type, int Log2LMUL, getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors); llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
static llvm::SmallVector<PrototypeDescriptor> static llvm::SmallVector<PrototypeDescriptor>

View File

@ -132,6 +132,7 @@ class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
private: private:
Sema &S; Sema &S;
ASTContext &Context; ASTContext &Context;
RVVTypeCache TypeCache;
// List of all RVV intrinsic. // List of all RVV intrinsic.
std::vector<RVVIntrinsicDef> IntrinsicList; std::vector<RVVIntrinsicDef> IntrinsicList;
@ -247,16 +248,16 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
continue; continue;
Optional<RVVTypes> Types = Optional<RVVTypes> Types =
RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq); TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
// Ignored to create new intrinsic if there are any illegal types. // Ignored to create new intrinsic if there are any illegal types.
if (!Types.has_value()) if (!Types.has_value())
continue; continue;
std::string SuffixStr = std::string SuffixStr = RVVIntrinsic::getSuffixStr(
RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto); TypeCache, BaseType, Log2LMUL, SuffixProto);
std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
BaseType, Log2LMUL, OverloadedSuffixProto); TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto);
// Create non-masked intrinsic. // Create non-masked intrinsic.
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types, InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types,
@ -271,7 +272,7 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
BasicProtoSeq, /*IsMasked=*/false, BasicProtoSeq, /*IsMasked=*/false,
/*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF, /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF,
Record.IsPrototypeDefaultTU, UnMaskedPolicyScheme, P); Record.IsPrototypeDefaultTU, UnMaskedPolicyScheme, P);
Optional<RVVTypes> PolicyTypes = RVVType::computeTypes( Optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
BaseType, Log2LMUL, Record.NF, PolicyPrototype); BaseType, Log2LMUL, Record.NF, PolicyPrototype);
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
/*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy, /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy,
@ -282,7 +283,7 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
continue; continue;
// Create masked intrinsic. // Create masked intrinsic.
Optional<RVVTypes> MaskTypes = Optional<RVVTypes> MaskTypes =
RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq); TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true, InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
*MaskTypes, MaskedHasPolicy, Policy::PolicyNone, *MaskTypes, MaskedHasPolicy, Policy::PolicyNone,
Record.IsPrototypeDefaultTU); Record.IsPrototypeDefaultTU);
@ -295,7 +296,7 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand,
Record.HasVL, Record.NF, Record.IsPrototypeDefaultTU, Record.HasVL, Record.NF, Record.IsPrototypeDefaultTU,
MaskedPolicyScheme, P); MaskedPolicyScheme, P);
Optional<RVVTypes> PolicyTypes = RVVType::computeTypes( Optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
BaseType, Log2LMUL, Record.NF, PolicyPrototype); BaseType, Log2LMUL, Record.NF, PolicyPrototype);
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
/*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P, /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P,

View File

@ -16,8 +16,6 @@
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <numeric> #include <numeric>
#include <set>
#include <unordered_map>
using namespace llvm; using namespace llvm;
@ -786,7 +784,7 @@ void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
} }
Optional<RVVTypes> Optional<RVVTypes>
RVVType::computeTypes(BasicType BT, int Log2LMUL, unsigned NF, RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
ArrayRef<PrototypeDescriptor> Prototype) { ArrayRef<PrototypeDescriptor> Prototype) {
// LMUL x NF must be less than or equal to 8. // LMUL x NF must be less than or equal to 8.
if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8) if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
@ -816,11 +814,8 @@ static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
((uint64_t)(Proto.VTM & 0xff) << 32); ((uint64_t)(Proto.VTM & 0xff) << 32);
} }
Optional<RVVTypePtr> RVVType::computeType(BasicType BT, int Log2LMUL, Optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
PrototypeDescriptor Proto) { PrototypeDescriptor Proto) {
// Concat BasicType, LMUL and Proto as key
static std::unordered_map<uint64_t, RVVType> LegalTypes;
static std::set<uint64_t> IllegalTypes;
uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto); uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
// Search first // Search first
auto It = LegalTypes.find(Idx); auto It = LegalTypes.find(Idx);
@ -834,8 +829,9 @@ Optional<RVVTypePtr> RVVType::computeType(BasicType BT, int Log2LMUL,
RVVType T(BT, Log2LMUL, Proto); RVVType T(BT, Log2LMUL, Proto);
if (T.isValid()) { if (T.isValid()) {
// Record legal type index and value. // Record legal type index and value.
LegalTypes.insert({Idx, T}); std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
return &(LegalTypes[Idx]); InsertResult = LegalTypes.insert({Idx, T});
return &(InsertResult.first->second);
} }
// Record illegal type index. // Record illegal type index.
IllegalTypes.insert(Idx); IllegalTypes.insert(Idx);
@ -900,11 +896,11 @@ std::string RVVIntrinsic::getBuiltinTypeStr() const {
} }
std::string RVVIntrinsic::getSuffixStr( std::string RVVIntrinsic::getSuffixStr(
BasicType Type, int Log2LMUL, RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) { llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
SmallVector<std::string> SuffixStrs; SmallVector<std::string> SuffixStrs;
for (auto PD : PrototypeDescriptors) { for (auto PD : PrototypeDescriptors) {
auto T = RVVType::computeType(Type, Log2LMUL, PD); auto T = TypeCache.computeType(Type, Log2LMUL, PD);
SuffixStrs.push_back((*T)->getShortStr()); SuffixStrs.push_back((*T)->getShortStr());
} }
return join(SuffixStrs, "_"); return join(SuffixStrs, "_");

View File

@ -95,6 +95,7 @@ public:
class RVVEmitter { class RVVEmitter {
private: private:
RecordKeeper &Records; RecordKeeper &Records;
RVVTypeCache TypeCache;
public: public:
RVVEmitter(RecordKeeper &R) : Records(R) {} RVVEmitter(RecordKeeper &R) : Records(R) {}
@ -349,7 +350,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
// Print RVV boolean types. // Print RVV boolean types.
for (int Log2LMUL : Log2LMULs) { for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BasicType::Int8, Log2LMUL, auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL,
PrototypeDescriptor::Mask); PrototypeDescriptor::Mask);
if (T) if (T)
printType(T.value()); printType(T.value());
@ -358,10 +359,10 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
for (char I : StringRef("csil")) { for (char I : StringRef("csil")) {
BasicType BT = ParseBasicType(I); BasicType BT = ParseBasicType(I);
for (int Log2LMUL : Log2LMULs) { for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
if (T) { if (T) {
printType(T.value()); printType(T.value());
auto UT = RVVType::computeType( auto UT = TypeCache.computeType(
BT, Log2LMUL, BT, Log2LMUL,
PrototypeDescriptor(BaseTypeModifier::Vector, PrototypeDescriptor(BaseTypeModifier::Vector,
VectorTypeModifier::NoModifier, VectorTypeModifier::NoModifier,
@ -372,7 +373,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
} }
OS << "#if defined(__riscv_zvfh)\n"; OS << "#if defined(__riscv_zvfh)\n";
for (int Log2LMUL : Log2LMULs) { for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BasicType::Float16, Log2LMUL, auto T = TypeCache.computeType(BasicType::Float16, Log2LMUL,
PrototypeDescriptor::Vector); PrototypeDescriptor::Vector);
if (T) if (T)
printType(T.value()); printType(T.value());
@ -381,7 +382,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
OS << "#if (__riscv_v_elen_fp >= 32)\n"; OS << "#if (__riscv_v_elen_fp >= 32)\n";
for (int Log2LMUL : Log2LMULs) { for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BasicType::Float32, Log2LMUL, auto T = TypeCache.computeType(BasicType::Float32, Log2LMUL,
PrototypeDescriptor::Vector); PrototypeDescriptor::Vector);
if (T) if (T)
printType(T.value()); printType(T.value());
@ -390,7 +391,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
OS << "#if (__riscv_v_elen_fp >= 64)\n"; OS << "#if (__riscv_v_elen_fp >= 64)\n";
for (int Log2LMUL : Log2LMULs) { for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BasicType::Float64, Log2LMUL, auto T = TypeCache.computeType(BasicType::Float64, Log2LMUL,
PrototypeDescriptor::Vector); PrototypeDescriptor::Vector);
if (T) if (T)
printType(T.value()); printType(T.value());
@ -553,14 +554,15 @@ void RVVEmitter::createRVVIntrinsics(
for (int Log2LMUL : Log2LMULList) { for (int Log2LMUL : Log2LMULList) {
BasicType BT = ParseBasicType(I); BasicType BT = ParseBasicType(I);
Optional<RVVTypes> Types = Optional<RVVTypes> Types =
RVVType::computeTypes(BT, Log2LMUL, NF, Prototype); TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
// Ignored to create new intrinsic if there are any illegal types. // Ignored to create new intrinsic if there are any illegal types.
if (!Types) if (!Types)
continue; continue;
auto SuffixStr = RVVIntrinsic::getSuffixStr(BT, Log2LMUL, SuffixDesc); auto SuffixStr =
auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc);
RVVIntrinsic::getSuffixStr(BT, Log2LMUL, OverloadedSuffixDesc); auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
TypeCache, BT, Log2LMUL, OverloadedSuffixDesc);
// Create a unmasked intrinsic // Create a unmasked intrinsic
Out.push_back(std::make_unique<RVVIntrinsic>( Out.push_back(std::make_unique<RVVIntrinsic>(
Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
@ -576,7 +578,7 @@ void RVVEmitter::createRVVIntrinsics(
/*HasMaskedOffOperand=*/false, HasVL, NF, /*HasMaskedOffOperand=*/false, HasVL, NF,
IsPrototypeDefaultTU, UnMaskedPolicyScheme, P); IsPrototypeDefaultTU, UnMaskedPolicyScheme, P);
Optional<RVVTypes> PolicyTypes = Optional<RVVTypes> PolicyTypes =
RVVType::computeTypes(BT, Log2LMUL, NF, PolicyPrototype); TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
Out.push_back(std::make_unique<RVVIntrinsic>( Out.push_back(std::make_unique<RVVIntrinsic>(
Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
/*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
@ -588,7 +590,7 @@ void RVVEmitter::createRVVIntrinsics(
continue; continue;
// Create a masked intrinsic // Create a masked intrinsic
Optional<RVVTypes> MaskTypes = Optional<RVVTypes> MaskTypes =
RVVType::computeTypes(BT, Log2LMUL, NF, Prototype); TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
Out.push_back(std::make_unique<RVVIntrinsic>( Out.push_back(std::make_unique<RVVIntrinsic>(
Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName, Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName,
/*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,
@ -603,7 +605,7 @@ void RVVEmitter::createRVVIntrinsics(
BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
NF, IsPrototypeDefaultTU, MaskedPolicyScheme, P); NF, IsPrototypeDefaultTU, MaskedPolicyScheme, P);
Optional<RVVTypes> PolicyTypes = Optional<RVVTypes> PolicyTypes =
RVVType::computeTypes(BT, Log2LMUL, NF, PolicyPrototype); TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
Out.push_back(std::make_unique<RVVIntrinsic>( Out.push_back(std::make_unique<RVVIntrinsic>(
Name, SuffixStr, OverloadedName, OverloadedSuffixStr, Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,