Skip to content

Commit 89ea9df

Browse files
authored
[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).
1 parent 24f5385 commit 89ea9df

File tree

1 file changed

+51
-57
lines changed

1 file changed

+51
-57
lines changed

llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -455,15 +455,9 @@ struct FnAttributeComparator {
455455

456456
struct AttributeComparator {
457457
bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
458-
// Order all intrinsics with no functiona attributes before all intrinsics
459-
// with function attributes.
460-
bool HasFnAttrLHS = hasFnAttributes(*L);
461-
bool HasFnAttrRHS = hasFnAttributes(*R);
462-
463-
// Order by argument attributes if function `hasFnAttributes` is equal.
464-
// This is reliable because each side is already sorted internally.
465-
return std::tie(HasFnAttrLHS, L->ArgumentAttributes) <
466-
std::tie(HasFnAttrRHS, R->ArgumentAttributes);
458+
// This comparator is used to unique just the argument attributes of an
459+
// intrinsic without considering any function attributes.
460+
return L->ArgumentAttributes < R->ArgumentAttributes;
467461
}
468462
};
469463
} // End anonymous namespace
@@ -659,87 +653,85 @@ static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
659653
//
660654
// getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo));
661655
//
662-
// Create a table that records, for each argument attributes, the set of
656+
// Create a table that records, for each argument attributes, the list of
663657
// <ArgNo, ArgAttrID> pairs that are needed to construct its argument
664658
// attributes. These tables for all intrinsics will be concatenated into one
665659
// large table and then for each intrinsic, we remember the Staring index and
666660
// number of size of its slice of entries (i.e., number of arguments with
667661
// non-empty attributes), so that we can build the attribute list for an
668662
// intrinsic without using a switch-case.
669663

670-
// Find the max number of attributes to create the local array and create
671-
// a concatenated list of <ArgNo, AttrID> pairs.
672-
struct ArgNoAttrIDPair {
673-
uint16_t ArgNo, ArgAttrID;
674-
ArgNoAttrIDPair(uint16_t ArgNo, uint16_t ArgAttrID)
675-
: ArgNo(ArgNo), ArgAttrID(ArgAttrID) {}
676-
};
664+
using ArgNoAttrIDPair = std::pair<uint16_t, uint16_t>;
677665

678-
// For each unique ID in UniqAttributes, reacord the starting index in the
679-
// flattened ArgNoAttrIDPair table, and the number of non-empty arg
680-
// attributes.
681-
struct ArgAttributesInfo {
682-
uint16_t StartIndex;
683-
uint16_t NumAttrs;
684-
ArgAttributesInfo(uint16_t StartIndex, uint16_t NumAttrs)
685-
: StartIndex(StartIndex), NumAttrs(NumAttrs) {}
686-
};
687-
SmallVector<ArgNoAttrIDPair> ArgAttrIdTable;
688-
SmallVector<ArgAttributesInfo> ArgAttributesInfoTable(UniqAttributes.size(),
689-
{0, 0});
666+
// Emit the table of concatenated <ArgNo, AttrId> using SequenceToOffsetTable
667+
// so that entries can be reused if possible. Individual sequences in this
668+
// table do not have any terminator.
669+
using ArgAttrIDSubTable = SmallVector<ArgNoAttrIDPair>;
670+
SequenceToOffsetTable<ArgAttrIDSubTable> ArgAttrIdSequenceTable(std::nullopt);
671+
SmallVector<ArgAttrIDSubTable> ArgAttrIdSubTables(
672+
UniqAttributes.size()); // Indexed by UniqueID.
690673

674+
// Find the max number of attributes to create the local array.
691675
unsigned MaxNumAttrs = 0;
692676
for (const auto [IntPtr, UniqueID] : UniqAttributes) {
693677
const CodeGenIntrinsic &Int = *IntPtr;
694-
unsigned NumAttrs = 0;
695-
unsigned StartIndex = ArgAttrIdTable.size();
678+
ArgAttrIDSubTable SubTable;
696679

697680
for (const auto &[ArgNo, Attrs] : enumerate(Int.ArgumentAttributes)) {
698681
if (Attrs.empty())
699682
continue;
700683

701684
uint16_t ArgAttrID = UniqArgAttributes.find(Attrs)->second;
702-
ArgAttrIdTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
703-
++NumAttrs;
685+
SubTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
704686
}
705-
706-
// Record the start index and size of the list for this unique ID.
707-
if (NumAttrs)
708-
ArgAttributesInfoTable[UniqueID] =
709-
ArgAttributesInfo(StartIndex, NumAttrs);
710-
711-
NumAttrs += hasFnAttributes(Int);
687+
ArgAttrIdSubTables[UniqueID] = SubTable;
688+
if (!SubTable.empty())
689+
ArgAttrIdSequenceTable.add(SubTable);
690+
unsigned NumAttrs = SubTable.size() + hasFnAttributes(Int);
712691
MaxNumAttrs = std::max(MaxNumAttrs, NumAttrs);
713692
}
714693

715-
if (ArgAttrIdTable.size() >= std::numeric_limits<uint16_t>::max())
694+
ArgAttrIdSequenceTable.layout();
695+
696+
if (ArgAttrIdSequenceTable.size() >= std::numeric_limits<uint16_t>::max())
716697
PrintFatalError("Size of ArgAttrIdTable exceeds supported limit");
717698

718-
// Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttrIdTableIndex
719-
OS << R"(
720-
namespace {
721-
struct ArgNoAttrIDPair {
699+
// Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttributesInfoTable.
700+
OS << formatv(R"(
701+
namespace {{
702+
struct ArgNoAttrIDPair {{
722703
uint16_t ArgNo, ArgAttrID;
723704
};
724705
} // namespace
725706
726-
static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {
727-
)";
728-
for (const auto &[ArgNo, ArgAttrID] : ArgAttrIdTable)
729-
OS << formatv(" {{{}, {}},\n", ArgNo, ArgAttrID);
730-
OS << R"(}; // ArgAttrIdTable
707+
// Number of entries: {}
708+
static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {{
709+
)",
710+
ArgAttrIdSequenceTable.size());
731711

732-
namespace {
733-
struct ArgAttributesInfo {
712+
ArgAttrIdSequenceTable.emit(OS, [](raw_ostream &OS, ArgNoAttrIDPair Elem) {
713+
OS << formatv("{{{}, {}}", Elem.first, Elem.second);
714+
});
715+
716+
OS << formatv(R"(}; // ArgAttrIdTable
717+
718+
namespace {{
719+
struct ArgAttributesInfo {{
734720
uint16_t StartIndex;
735721
uint16_t NumAttrs;
736722
};
737723
} // namespace
738-
739-
static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {
740-
)";
741-
for (const auto &[StartIndex, NumAttrs] : ArgAttributesInfoTable)
724+
725+
// Number of entries: {}
726+
static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {{
727+
)",
728+
ArgAttrIdSubTables.size());
729+
730+
for (const auto &SubTable : ArgAttrIdSubTables) {
731+
unsigned NumAttrs = SubTable.size();
732+
unsigned StartIndex = NumAttrs ? ArgAttrIdSequenceTable.get(SubTable) : 0;
742733
OS << formatv(" {{{}, {}},\n", StartIndex, NumAttrs);
734+
}
743735
OS << "}; // ArgAttributesInfoTable\n";
744736

745737
// Now emit the Intrinsic::getAttributes function. This will first map
@@ -756,7 +748,9 @@ AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
756748
uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
757749
uint8_t FnAttrID = PackedID >> 8;
758750
uint8_t ArgAttrID = PackedID & 0xFF;
759-
std::pair<unsigned, AttributeSet> AS[{}];
751+
using PairTy = std::pair<unsigned, AttributeSet>;
752+
alignas(PairTy) char ASStorage[sizeof(PairTy) * {}];
753+
PairTy *AS = reinterpret_cast<PairTy *>(ASStorage);
760754
761755
// Construct an ArrayRef for easier range checking.
762756
ArrayRef<ArgAttributesInfo> ArgAttributesInfoTableAR(ArgAttributesInfoTable);

0 commit comments

Comments
 (0)