@@ -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
622625static 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
716784void IntrinsicEmitter::EmitIntrinsicToBuiltinMap (
0 commit comments