diff options
Diffstat (limited to 'llvm/utils')
-rw-r--r-- | llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp | 176 |
1 files changed, 122 insertions, 54 deletions
diff --git a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp index 49f7194..293e64e 100644 --- a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp @@ -561,7 +561,8 @@ static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID, } // getIntrinsicArgAttributeSet )"; - // Compute unique function attribute sets. + // Compute unique function attribute sets. Note that ID 255 will be used for + // intrinsics with no function attributes. std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator> UniqFnAttributes; OS << R"( @@ -570,6 +571,8 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { default: llvm_unreachable("Invalid attribute set number");)"; for (const CodeGenIntrinsic &Int : Ints) { + if (!hasFnAttributes(Int)) + continue; unsigned ID = UniqFnAttributes.size(); if (!UniqFnAttributes.try_emplace(&Int, ID).second) continue; @@ -621,9 +624,7 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { static constexpr uint16_t IntrinsicsToAttributesMap[] = {)"; - // Compute the maximum number of attribute arguments and the map. For function - // attributes, we only consider whether the intrinsics has any function - // arguments or not. + // Compute unique argument attributes. std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator> UniqAttributes; for (const CodeGenIntrinsic &Int : Ints) { @@ -631,86 +632,153 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)"; UniqAttributes.try_emplace(&Int, ID); } - // Emit an array of AttributeList. Most intrinsics will have at least one - // entry, for the function itself (index ~1), which is usually nounwind. - for (const CodeGenIntrinsic &Int : Ints) { - uint16_t FnAttrIndex = UniqFnAttributes[&Int]; - OS << formatv("\n {} << 8 | {}, // {}", FnAttrIndex, - UniqAttributes[&Int], Int.Name); - } + constexpr uint16_t NoFunctionAttrsID = 255; + if (UniqAttributes.size() > 256) + PrintFatalError("Too many unique argument attributes for table!"); + // Note, ID 255 is used to indicate no function attributes. + if (UniqFnAttributes.size() > 255) + PrintFatalError("Too many unique function attributes for table!"); // Assign a 16-bit packed ID for each intrinsic. The lower 8-bits will be its // "argument attribute ID" (index in UniqAttributes) and upper 8 bits will be // its "function attribute ID" (index in UniqFnAttributes). - if (UniqAttributes.size() > 256) - PrintFatalError("Too many unique argument attributes for table!"); - if (UniqFnAttributes.size() > 256) - PrintFatalError("Too many unique function attributes for table!"); + for (const CodeGenIntrinsic &Int : Ints) { + uint16_t FnAttrIndex = + hasFnAttributes(Int) ? UniqFnAttributes[&Int] : NoFunctionAttrsID; + OS << formatv("\n {} << 8 | {}, // {}", FnAttrIndex, + UniqAttributes[&Int], Int.Name); + } OS << R"( -}; +}; // IntrinsicsToAttributesMap +)"; + + // For a given intrinsic, its attributes are constructed by populating the + // local array `AS` below with its non-empty argument attributes followed by + // function attributes if any. Each argument attribute is constructed as: + // + // getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo)); + // + // Create a table that records, for each argument attributes, the set of + // <ArgNo, ArgAttrID> pairs that are needed to construct its argument + // attributes. These tables for all intrinsics will be concatenated into one + // large table and then for each intrinsic, we remember the Staring index and + // number of size of its slice of entries (i.e., number of arguments with + // non-empty attributes), so that we can build the attribute list for an + // intrinsic without using a switch-case. + + // Find the max number of attributes to create the local array and create + // a concatenated list of <ArgNo, AttrID> pairs. + struct ArgNoAttrIDPair { + uint16_t ArgNo, ArgAttrID; + ArgNoAttrIDPair(uint16_t ArgNo, uint16_t ArgAttrID) + : ArgNo(ArgNo), ArgAttrID(ArgAttrID) {} + }; + + // For each unique ID in UniqAttributes, reacord the starting index in the + // flattened ArgNoAttrIDPair table, and the number of non-empty arg + // attributes. + struct ArgAttributesInfo { + uint16_t StartIndex; + uint16_t NumAttrs; + ArgAttributesInfo(uint16_t StartIndex, uint16_t NumAttrs) + : StartIndex(StartIndex), NumAttrs(NumAttrs) {} + }; + SmallVector<ArgNoAttrIDPair> ArgAttrIdTable; + SmallVector<ArgAttributesInfo> ArgAttributesInfoTable(UniqAttributes.size(), + {0, 0}); -AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id, - FunctionType *FT) {)"; - // Find the max number of attributes to create the local array. unsigned MaxNumAttrs = 0; for (const auto [IntPtr, UniqueID] : UniqAttributes) { const CodeGenIntrinsic &Int = *IntPtr; - unsigned NumAttrs = - llvm::count_if(Int.ArgumentAttributes, - [](const auto &Attrs) { return !Attrs.empty(); }); + unsigned NumAttrs = 0; + unsigned StartIndex = ArgAttrIdTable.size(); + + for (const auto &[ArgNo, Attrs] : enumerate(Int.ArgumentAttributes)) { + if (Attrs.empty()) + continue; + + uint16_t ArgAttrID = UniqArgAttributes.find(Attrs)->second; + ArgAttrIdTable.emplace_back((uint16_t)ArgNo, ArgAttrID); + ++NumAttrs; + } + + // Record the start index and size of the list for this unique ID. + if (NumAttrs) + ArgAttributesInfoTable[UniqueID] = + ArgAttributesInfo(StartIndex, NumAttrs); + NumAttrs += hasFnAttributes(Int); MaxNumAttrs = std::max(MaxNumAttrs, NumAttrs); } + if (ArgAttrIdTable.size() >= std::numeric_limits<uint16_t>::max()) + PrintFatalError("Size of ArgAttrIdTable exceeds supported limit"); + + // Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttrIdTableIndex + OS << R"( +namespace { +struct ArgNoAttrIDPair { + uint16_t ArgNo, ArgAttrID; +}; +} // namespace + +static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = { +)"; + for (const auto &[ArgNo, ArgAttrID] : ArgAttrIdTable) + OS << formatv(" {{{}, {}},\n", ArgNo, ArgAttrID); + OS << R"(}; // ArgAttrIdTable + +namespace { +struct ArgAttributesInfo { + uint16_t StartIndex; + uint16_t NumAttrs; +}; +} // namespace + +static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = { +)"; + for (const auto &[StartIndex, NumAttrs] : ArgAttributesInfoTable) + OS << formatv(" {{{}, {}},\n", StartIndex, NumAttrs); + OS << "}; // ArgAttributesInfoTable\n"; + + // Now emit the Intrinsic::getAttributes function. This will first map + // from intrinsic ID -> unique arg/function attr ID (using the + // IntrinsicsToAttributesMap) table. Then it will use the unique arg ID to + // construct all the argument attributes (using the ArgAttributesInfoTable and + // ArgAttrIdTable) and then add on the function attributes if any. OS << formatv(R"( +AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id, + FunctionType *FT) {{ if (id == 0) return AttributeList(); uint16_t PackedID = IntrinsicsToAttributesMap[id - 1]; uint8_t FnAttrID = PackedID >> 8; + uint8_t ArgAttrID = PackedID & 0xFF; std::pair<unsigned, AttributeSet> AS[{}]; - unsigned NumAttrs = 0; - bool HasFnAttr = false; - switch(PackedID & 0xFF) {{ - default: llvm_unreachable("Invalid attribute number"); -)", - MaxNumAttrs); - for (const auto [IntPtr, UniqueID] : UniqAttributes) { - OS << formatv(" case {}:\n", UniqueID); - const CodeGenIntrinsic &Int = *IntPtr; - - unsigned NumAttrs = 0; - - for (const auto &[AttrIdx, Attrs] : enumerate(Int.ArgumentAttributes)) { - if (Attrs.empty()) - continue; + // Construct an ArrayRef for easier range checking. + ArrayRef<ArgAttributesInfo> ArgAttributesInfoTableAR(ArgAttributesInfoTable); + if (ArgAttrID >= ArgAttributesInfoTableAR.size()) + llvm_unreachable("Invalid arguments attribute ID"); - unsigned ArgAttrID = UniqArgAttributes.find(Attrs)->second; - OS << formatv(" AS[{}] = {{{}, getIntrinsicArgAttributeSet(C, {}, " - "FT->getContainedType({}))};\n", - NumAttrs++, AttrIdx, ArgAttrID, AttrIdx); - } - - if (hasFnAttributes(Int)) - OS << " HasFnAttr = true;\n"; - - if (NumAttrs) - OS << formatv(" NumAttrs = {};\n", NumAttrs); - OS << " break;\n"; + auto [StartIndex, NumAttrs] = ArgAttributesInfoTableAR[ArgAttrID]; + for (unsigned Idx = 0; Idx < NumAttrs; ++Idx) {{ + auto [ArgNo, ArgAttrID] = ArgAttrIdTable[StartIndex + Idx]; + AS[Idx] = {{ArgNo, + getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo))}; } - - OS << R"( } - if (HasFnAttr) { - AS[NumAttrs++] = {AttributeList::FunctionIndex, + if (FnAttrID != {}) { + AS[NumAttrs++] = {{AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, FnAttrID)}; } return AttributeList::get(C, ArrayRef(AS, NumAttrs)); } #endif // GET_INTRINSIC_ATTRIBUTES -)"; +)", + MaxNumAttrs, NoFunctionAttrsID); } void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( |