Skip to content

Commit 6aede33

Browse files
committed
[NFCI][TableGen] Make Intrinsic::getAttributes table driven
1 parent 5342c33 commit 6aede33

File tree

2 files changed

+132
-62
lines changed

2 files changed

+132
-62
lines changed

llvm/test/TableGen/intrinsic-attrs.td

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,16 @@ def int_deref_ptr_ret : Intrinsic<[llvm_ptr_ty], [], [Dereferenceable<RetIndex,
2727
// CHECK: static constexpr uint16_t IntrinsicsToAttributesMap[] = {
2828
// CHECK: 0 << 8 | 0, // llvm.deref.ptr.ret
2929
// CHECK: 1 << 8 | 1, // llvm.random.gen
30+
// CHECK: }; // IntrinsicsToAttributesMap
31+
32+
// CHECK: static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {
33+
// CHECK-NEXT: {0, 0},
34+
// CHECK: }; // ArgAttrIdTable
35+
36+
// CHECK: static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {
37+
// CHECK-NEXT: {0, 1},
38+
// CHECK-NEXT: {0, 0},
39+
// CHECK-NEXT: }; // ArgAttributesInfoTable
3040

3141
// CHECK: getAttributes(LLVMContext &C, ID id,
3242
// CHECK-NEXT: FunctionType *FT) {
33-
// CHECK: case 1:
34-
// CHECK-NEXT: HasFnAttr = true;
35-
// CHECK-NEXT: break;
36-
// CHECK-NEXT: case 0:
37-
// CHECK-NEXT: AS[0] = {0, getIntrinsicArgAttributeSet(C, 0, FT->getContainedType(0))};
38-
// CHECK-NEXT: HasFnAttr = true;
39-
// CHECK-NEXT: NumAttrs = 1
40-
// CHECK-NEXT: break;

llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp

Lines changed: 122 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,8 @@ static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID,
561561
} // getIntrinsicArgAttributeSet
562562
)";
563563

564-
// Compute unique function attribute sets.
564+
// Compute unique function attribute sets. Note that ID 255 will be used for
565+
// intrinsics with no function attributes.
565566
std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator>
566567
UniqFnAttributes;
567568
OS << R"(
@@ -570,6 +571,8 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) {
570571
default: llvm_unreachable("Invalid attribute set number");)";
571572

572573
for (const CodeGenIntrinsic &Int : Ints) {
574+
if (!hasFnAttributes(Int))
575+
continue;
573576
unsigned ID = UniqFnAttributes.size();
574577
if (!UniqFnAttributes.try_emplace(&Int, ID).second)
575578
continue;
@@ -621,96 +624,161 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) {
621624
622625
static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
623626

624-
// Compute the maximum number of attribute arguments and the map. For function
625-
// attributes, we only consider whether the intrinsics has any function
626-
// arguments or not.
627+
// Compute unique argument attributes.
627628
std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator>
628629
UniqAttributes;
629630
for (const CodeGenIntrinsic &Int : Ints) {
630631
unsigned ID = UniqAttributes.size();
631632
UniqAttributes.try_emplace(&Int, ID);
632633
}
633634

634-
// Emit an array of AttributeList. Most intrinsics will have at least one
635-
// entry, for the function itself (index ~1), which is usually nounwind.
636-
for (const CodeGenIntrinsic &Int : Ints) {
637-
uint16_t FnAttrIndex = UniqFnAttributes[&Int];
638-
OS << formatv("\n {} << 8 | {}, // {}", FnAttrIndex,
639-
UniqAttributes[&Int], Int.Name);
640-
}
635+
constexpr uint16_t NoFunctionAttrsID = 255;
636+
if (UniqAttributes.size() > 256)
637+
PrintFatalError("Too many unique argument attributes for table!");
638+
// Note, ID 255 is used to indicate no function attributes.
639+
if (UniqFnAttributes.size() > 255)
640+
PrintFatalError("Too many unique function attributes for table!");
641641

642642
// Assign a 16-bit packed ID for each intrinsic. The lower 8-bits will be its
643643
// "argument attribute ID" (index in UniqAttributes) and upper 8 bits will be
644644
// its "function attribute ID" (index in UniqFnAttributes).
645-
if (UniqAttributes.size() > 256)
646-
PrintFatalError("Too many unique argument attributes for table!");
647-
if (UniqFnAttributes.size() > 256)
648-
PrintFatalError("Too many unique function attributes for table!");
645+
for (const CodeGenIntrinsic &Int : Ints) {
646+
uint16_t FnAttrIndex =
647+
hasFnAttributes(Int) ? UniqFnAttributes[&Int] : NoFunctionAttrsID;
648+
OS << formatv("\n {} << 8 | {}, // {}", FnAttrIndex,
649+
UniqAttributes[&Int], Int.Name);
650+
}
649651

650652
OS << R"(
651-
};
653+
}; // IntrinsicsToAttributesMap
654+
)";
655+
656+
// For a given intrinsic, its attributes are constructed by populating the
657+
// local array `AS` below with its non-empty argument attributes followed by
658+
// function attributes if any. Each argument attribute is constructed as:
659+
//
660+
// getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo));
661+
//
662+
// Create a table that records, for each argument attributes, the set of
663+
// <ArgNo, ArgAttrID> pairs that are needed to construct its argument
664+
// attributes. These tables for all intrinsics will be concatenated into one
665+
// large table and then for each intrinsic, we remember the Staring index and
666+
// number of size of its slice of entries (i.e., number of arguments with
667+
// non-empty attributes), so that we can build the attribute list for an
668+
// intrinsic without using a switch-case.
669+
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+
};
677+
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});
652690

653-
AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
654-
FunctionType *FT) {)";
655-
// Find the max number of attributes to create the local array.
656691
unsigned MaxNumAttrs = 0;
657692
for (const auto [IntPtr, UniqueID] : UniqAttributes) {
658693
const CodeGenIntrinsic &Int = *IntPtr;
659-
unsigned NumAttrs =
660-
llvm::count_if(Int.ArgumentAttributes,
661-
[](const auto &Attrs) { return !Attrs.empty(); });
694+
unsigned NumAttrs = 0;
695+
unsigned StartIndex = ArgAttrIdTable.size();
696+
697+
for (const auto &[ArgNo, Attrs] : enumerate(Int.ArgumentAttributes)) {
698+
if (Attrs.empty())
699+
continue;
700+
701+
uint16_t ArgAttrID = UniqArgAttributes.find(Attrs)->second;
702+
ArgAttrIdTable.emplace_back((uint16_t)ArgNo, ArgAttrID);
703+
++NumAttrs;
704+
}
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+
662711
NumAttrs += hasFnAttributes(Int);
663712
MaxNumAttrs = std::max(MaxNumAttrs, NumAttrs);
664713
}
665714

715+
if (ArgAttrIdTable.size() >= std::numeric_limits<uint16_t>::max())
716+
PrintFatalError("Size of ArgAttrIdTable exceeds supported limit");
717+
718+
// Emit the 2 tables (flattened ArgNo, ArgAttrID) and ArgAttrIdTableIndex
719+
OS << R"(
720+
namespace {
721+
struct ArgNoAttrIDPair {
722+
uint16_t ArgNo, ArgAttrID;
723+
};
724+
} // namespace
725+
726+
static constexpr ArgNoAttrIDPair ArgAttrIdTable[] = {
727+
)";
728+
for (const auto &[ArgNo, ArgAttrID] : ArgAttrIdTable)
729+
OS << formatv(" {{{}, {}},\n", ArgNo, ArgAttrID);
730+
OS << R"(}; // ArgAttrIdTable
731+
732+
namespace {
733+
struct ArgAttributesInfo {
734+
uint16_t StartIndex;
735+
uint16_t NumAttrs;
736+
};
737+
} // namespace
738+
739+
static constexpr ArgAttributesInfo ArgAttributesInfoTable[] = {
740+
)";
741+
for (const auto &[StartIndex, NumAttrs] : ArgAttributesInfoTable)
742+
OS << formatv(" {{{}, {}},\n", StartIndex, NumAttrs);
743+
OS << "}; // ArgAttributesInfoTable\n";
744+
745+
// Now emit the Intrinsic::getAttributes function. This will first map
746+
// from intrinsic ID -> unique arg/function attr ID (using the
747+
// IntrinsicsToAttributesMap) table. Then it will use the unique arg ID to
748+
// construct all the argument attributes (using the ArgAttributesInfoTable and
749+
// ArgAttrIdTable) and then add on the function attributes if any.
666750
OS << formatv(R"(
751+
AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
752+
FunctionType *FT) {{
667753
if (id == 0)
668754
return AttributeList();
669755
670756
uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
671757
uint8_t FnAttrID = PackedID >> 8;
758+
uint8_t ArgAttrID = PackedID & 0xFF;
672759
std::pair<unsigned, AttributeSet> AS[{}];
673-
unsigned NumAttrs = 0;
674-
bool HasFnAttr = false;
675-
switch(PackedID & 0xFF) {{
676-
default: llvm_unreachable("Invalid attribute number");
677-
)",
678-
MaxNumAttrs);
679760
680-
for (const auto [IntPtr, UniqueID] : UniqAttributes) {
681-
OS << formatv(" case {}:\n", UniqueID);
682-
const CodeGenIntrinsic &Int = *IntPtr;
683-
684-
unsigned NumAttrs = 0;
685-
686-
for (const auto &[AttrIdx, Attrs] : enumerate(Int.ArgumentAttributes)) {
687-
if (Attrs.empty())
688-
continue;
761+
// Construct an ArrayRef for easier range checking.
762+
ArrayRef<ArgAttributesInfo> ArgAttributesInfoTableAR(ArgAttributesInfoTable);
763+
if (ArgAttrID >= ArgAttributesInfoTableAR.size())
764+
llvm_unreachable("Invalid arguments attribute ID");
689765
690-
unsigned ArgAttrID = UniqArgAttributes.find(Attrs)->second;
691-
OS << formatv(" AS[{}] = {{{}, getIntrinsicArgAttributeSet(C, {}, "
692-
"FT->getContainedType({}))};\n",
693-
NumAttrs++, AttrIdx, ArgAttrID, AttrIdx);
694-
}
695-
696-
if (hasFnAttributes(Int))
697-
OS << " HasFnAttr = true;\n";
698-
699-
if (NumAttrs)
700-
OS << formatv(" NumAttrs = {};\n", NumAttrs);
701-
OS << " break;\n";
766+
auto [StartIndex, NumAttrs] = ArgAttributesInfoTableAR[ArgAttrID];
767+
for (unsigned Idx = 0; Idx < NumAttrs; ++Idx) {{
768+
auto [ArgNo, ArgAttrID] = ArgAttrIdTable[StartIndex + Idx];
769+
AS[Idx] = {{ArgNo,
770+
getIntrinsicArgAttributeSet(C, ArgAttrID, FT->getContainedType(ArgNo))};
702771
}
703-
704-
OS << R"( }
705-
if (HasFnAttr) {
706-
AS[NumAttrs++] = {AttributeList::FunctionIndex,
772+
if (FnAttrID != {}) {
773+
AS[NumAttrs++] = {{AttributeList::FunctionIndex,
707774
getIntrinsicFnAttributeSet(C, FnAttrID)};
708775
}
709776
return AttributeList::get(C, ArrayRef(AS, NumAttrs));
710777
}
711778
#endif // GET_INTRINSIC_ATTRIBUTES
712779
713-
)";
780+
)",
781+
MaxNumAttrs, NoFunctionAttrsID);
714782
}
715783

716784
void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(

0 commit comments

Comments
 (0)