[NFCI[TableGen] Minor improvements to Intrinsic::getAttributes
(#152761)
This change implements several small improvements to `Intrinsic::getAttributes`: 1. Use `SequenceToOffsetTable` to emit `ArgAttrIdTable`. This enables reuse of entries when they share a common prefix. This reduces the size of this table from 546 to 484 entries, which is 248 bytes. 2. Fix `AttributeComparator` to purely compare argument attributes and not look at function attributes. This avoids unnecessary duplicates in the uniqueing process and eliminates 2 entries from `ArgAttributesInfoTable`, saving 8 bytes. 3. Improve `Intrinsic::getAttributes` code to not initialize all entries of `AS` always. Currently, we initialize all entries of the array `AS` even if we may not use all of them. In addition to the runtime cost, for Clang release builds, since the initialization loop is unrolled, it consumes ~330 bytes of code to initialize the `AS` array. Address this by declaring the storage for AS using just a char array with appropriate `alignas` (similar to how `SmallVectorStorage` defines its inline elements).
This commit is contained in:
parent
24f5385a85
commit
89ea9df6a2
@ -455,15 +455,9 @@ struct FnAttributeComparator {
|
|||||||
|
|
||||||
struct AttributeComparator {
|
struct AttributeComparator {
|
||||||
bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
|
bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
|
||||||
// Order all intrinsics with no functiona attributes before all intrinsics
|
// This comparator is used to unique just the argument attributes of an
|
||||||
// with function attributes.
|
// intrinsic without considering any function attributes.
|
||||||
bool HasFnAttrLHS = hasFnAttributes(*L);
|
return L->ArgumentAttributes < R->ArgumentAttributes;
|
||||||
bool HasFnAttrRHS = hasFnAttributes(*R);
|
|
||||||
|
|
||||||
// Order by argument attributes if function `hasFnAttributes` is equal.
|
|
||||||
// This is reliable because each side is already sorted internally.
|
|
||||||
return std::tie(HasFnAttrLHS, L->ArgumentAttributes) <
|
|
||||||
std::tie(HasFnAttrRHS, R->ArgumentAttributes);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // End anonymous namespace
|
} // End anonymous namespace
|
||||||
@ -659,7 +653,7 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
|
|||||||
//
|
//
|
||||||
// getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo));
|
// getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo));
|
||||||
//
|
//
|
||||||
// Create a table that records, for each argument attributes, the set of
|
// Create a table that records, for each argument attributes, the list of
|
||||||
// <ArgNo, ArgAttrID> pairs that are needed to construct its argument
|
// <ArgNo, ArgAttrID> pairs that are needed to construct its argument
|
||||||
// attributes. These tables for all intrinsics will be concatenated into one
|
// attributes. These tables for all intrinsics will be concatenated into one
|
||||||
// large table and then for each intrinsic, we remember the Staring index and
|
// large table and then for each intrinsic, we remember the Staring index and
|
||||||
@ -667,79 +661,77 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
|
|||||||
// non-empty attributes), so that we can build the attribute list for an
|
// non-empty attributes), so that we can build the attribute list for an
|
||||||
// intrinsic without using a switch-case.
|
// intrinsic without using a switch-case.
|
||||||
|
|
||||||
// Find the max number of attributes to create the local array and create
|
using ArgNoAttrIDPair = std::pair<uint16_t, uint16_t>;
|
||||||
// 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
|
// Emit the table of concatenated <ArgNo, AttrId> using SequenceToOffsetTable
|
||||||
// flattened ArgNoAttrIDPair table, and the number of non-empty arg
|
// so that entries can be reused if possible. Individual sequences in this
|
||||||
// attributes.
|
// table do not have any terminator.
|
||||||
struct ArgAttributesInfo {
|
using ArgAttrIDSubTable = SmallVector<ArgNoAttrIDPair>;
|
||||||
uint16_t StartIndex;
|
SequenceToOffsetTable<ArgAttrIDSubTable> ArgAttrIdSequenceTable(std::nullopt);
|
||||||
uint16_t NumAttrs;
|
SmallVector<ArgAttrIDSubTable> ArgAttrIdSubTables(
|
||||||
ArgAttributesInfo(uint16_t StartIndex, uint16_t NumAttrs)
|
UniqAttributes.size()); // Indexed by UniqueID.
|
||||||
: StartIndex(StartIndex), NumAttrs(NumAttrs) {}
|
|
||||||
};
|
|
||||||
SmallVector<ArgNoAttrIDPair> ArgAttrIdTable;
|
|
||||||
SmallVector<ArgAttributesInfo> ArgAttributesInfoTable(UniqAttributes.size(),
|
|
||||||
{0, 0});
|
|
||||||
|
|
||||||
|
// Find the max number of attributes to create the local array.
|
||||||
unsigned MaxNumAttrs = 0;
|
unsigned MaxNumAttrs = 0;
|
||||||
for (const auto [IntPtr, UniqueID] : UniqAttributes) {
|
for (const auto [IntPtr, UniqueID] : UniqAttributes) {
|
||||||
const CodeGenIntrinsic &Int = *IntPtr;
|
const CodeGenIntrinsic &Int = *IntPtr;
|
||||||
unsigned NumAttrs = 0;
|
ArgAttrIDSubTable SubTable;
|
||||||
unsigned StartIndex = ArgAttrIdTable.size();
|
|
||||||
|
|
||||||
for (const auto &[ArgNo, Attrs] : enumerate(Int.ArgumentAttributes)) {
|
for (const auto &[ArgNo, Attrs] : enumerate(Int.ArgumentAttributes)) {
|
||||||
if (Attrs.empty())
|
if (Attrs.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint16_t ArgAttrID = UniqArgAttributes.find(Attrs)->second;
|
uint16_t ArgAttrID = UniqArgAttributes.find(Attrs)->second;
|
||||||
ArgAttrIdTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
|
SubTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
|
||||||
++NumAttrs;
|
|
||||||
}
|
}
|
||||||
|
ArgAttrIdSubTables[UniqueID] = SubTable;
|
||||||
// Record the start index and size of the list for this unique ID.
|
if (!SubTable.empty())
|
||||||
if (NumAttrs)
|
ArgAttrIdSequenceTable.add(SubTable);
|
||||||
ArgAttributesInfoTable[UniqueID] =
|
unsigned NumAttrs = SubTable.size() + hasFnAttributes(Int);
|
||||||
ArgAttributesInfo(StartIndex, NumAttrs);
|
|
||||||
|
|
||||||
NumAttrs += hasFnAttributes(Int);
|
|
||||||
MaxNumAttrs = std::max(MaxNumAttrs, NumAttrs);
|
MaxNumAttrs = std::max(MaxNumAttrs, NumAttrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ArgAttrIdTable.size() >= std::numeric_limits<uint16_t>::max())
|
ArgAttrIdSequenceTable.layout();
|
||||||
|
|
||||||
|
if (ArgAttrIdSequenceTable.size() >= std::numeric_limits<uint16_t>::max())
|
||||||
PrintFatalError("Size of ArgAttrIdTable exceeds supported limit");
|
PrintFatalError("Size of ArgAttrIdTable exceeds supported limit");
|
||||||
|
|
||||||
// Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttrIdTableIndex
|
// Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttributesInfoTable.
|
||||||
OS << R"(
|
OS << formatv(R"(
|
||||||
namespace {
|
namespace {{
|
||||||
struct ArgNoAttrIDPair {
|
struct ArgNoAttrIDPair {{
|
||||||
uint16_t ArgNo, ArgAttrID;
|
uint16_t ArgNo, ArgAttrID;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {
|
// Number of entries: {}
|
||||||
)";
|
static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {{
|
||||||
for (const auto &[ArgNo, ArgAttrID] : ArgAttrIdTable)
|
)",
|
||||||
OS << formatv(" {{{}, {}},\n", ArgNo, ArgAttrID);
|
ArgAttrIdSequenceTable.size());
|
||||||
OS << R"(}; // ArgAttrIdTable
|
|
||||||
|
|
||||||
namespace {
|
ArgAttrIdSequenceTable.emit(OS, [](raw_ostream &OS, ArgNoAttrIDPair Elem) {
|
||||||
struct ArgAttributesInfo {
|
OS << formatv("{{{}, {}}", Elem.first, Elem.second);
|
||||||
|
});
|
||||||
|
|
||||||
|
OS << formatv(R"(}; // ArgAttrIdTable
|
||||||
|
|
||||||
|
namespace {{
|
||||||
|
struct ArgAttributesInfo {{
|
||||||
uint16_t StartIndex;
|
uint16_t StartIndex;
|
||||||
uint16_t NumAttrs;
|
uint16_t NumAttrs;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {
|
// Number of entries: {}
|
||||||
)";
|
static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {{
|
||||||
for (const auto &[StartIndex, NumAttrs] : ArgAttributesInfoTable)
|
)",
|
||||||
|
ArgAttrIdSubTables.size());
|
||||||
|
|
||||||
|
for (const auto &SubTable : ArgAttrIdSubTables) {
|
||||||
|
unsigned NumAttrs = SubTable.size();
|
||||||
|
unsigned StartIndex = NumAttrs ? ArgAttrIdSequenceTable.get(SubTable) : 0;
|
||||||
OS << formatv(" {{{}, {}},\n", StartIndex, NumAttrs);
|
OS << formatv(" {{{}, {}},\n", StartIndex, NumAttrs);
|
||||||
|
}
|
||||||
OS << "}; // ArgAttributesInfoTable\n";
|
OS << "}; // ArgAttributesInfoTable\n";
|
||||||
|
|
||||||
// Now emit the Intrinsic::getAttributes function. This will first map
|
// Now emit the Intrinsic::getAttributes function. This will first map
|
||||||
@ -756,7 +748,9 @@ AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
|
|||||||
uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
|
uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
|
||||||
uint8_t FnAttrID = PackedID >> 8;
|
uint8_t FnAttrID = PackedID >> 8;
|
||||||
uint8_t ArgAttrID = PackedID & 0xFF;
|
uint8_t ArgAttrID = PackedID & 0xFF;
|
||||||
std::pair<unsigned, AttributeSet> AS[{}];
|
using PairTy = std::pair<unsigned, AttributeSet>;
|
||||||
|
alignas(PairTy) char ASStorage[sizeof(PairTy) * {}];
|
||||||
|
PairTy *AS = reinterpret_cast<PairTy *>(ASStorage);
|
||||||
|
|
||||||
// Construct an ArrayRef for easier range checking.
|
// Construct an ArrayRef for easier range checking.
|
||||||
ArrayRef<ArgAttributesInfo> ArgAttributesInfoTableAR(ArgAttributesInfoTable);
|
ArrayRef<ArgAttributesInfo> ArgAttributesInfoTableAR(ArgAttributesInfoTable);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user