2929#include < array>
3030#include < cassert>
3131#include < cctype>
32+ #include < limits>
3233#include < map>
3334#include < optional>
3435#include < string>
@@ -379,8 +380,17 @@ static constexpr {} IIT_Table[] = {{
379380 OS << " #endif\n\n " ; // End of GET_INTRINSIC_GENERATOR_GLOBAL
380381}
381382
383+ // / Returns the effective MemoryEffects for intrinsic \p Int.
384+ static MemoryEffects getEffectiveME (const CodeGenIntrinsic &Int) {
385+ MemoryEffects ME = Int.ME ;
386+ // TODO: IntrHasSideEffects should affect not only readnone intrinsics.
387+ if (ME.doesNotAccessMemory () && Int.hasSideEffects )
388+ ME = MemoryEffects::unknown ();
389+ return ME;
390+ }
391+
382392static bool compareFnAttributes (const CodeGenIntrinsic *L,
383- const CodeGenIntrinsic *R, bool Default ) {
393+ const CodeGenIntrinsic *R) {
384394 auto TieBoolAttributes = [](const CodeGenIntrinsic *I) -> auto {
385395 // Sort throwing intrinsics after non-throwing intrinsics.
386396 return std::tie (I->canThrow , I->isNoDuplicate , I->isNoMerge , I->isNoReturn ,
@@ -396,50 +406,46 @@ static bool compareFnAttributes(const CodeGenIntrinsic *L,
396406 return TieL < TieR;
397407
398408 // Try to order by readonly/readnone attribute.
399- uint32_t LME = L-> ME .toIntValue ();
400- uint32_t RME = R-> ME .toIntValue ();
409+ uint32_t LME = getEffectiveME (*L) .toIntValue ();
410+ uint32_t RME = getEffectiveME (*R) .toIntValue ();
401411 if (LME != RME)
402412 return LME > RME;
403413
404- return Default;
414+ return false ;
415+ }
416+
417+ // / Returns true if \p Int has a non-empty set of function attributes. Note that
418+ // / NoUnwind = !canThrow, so we need to negate it's sense to test if the
419+ // intrinsic has NoUnwind attribute.
420+ static bool hasFnAttributes (const CodeGenIntrinsic &Int) {
421+ return !Int.canThrow || Int.isNoReturn || Int.isNoCallback || Int.isNoSync ||
422+ Int.isNoFree || Int.isWillReturn || Int.isCold || Int.isNoDuplicate ||
423+ Int.isNoMerge || Int.isConvergent || Int.isSpeculatable ||
424+ Int.isStrictFP || getEffectiveME (Int) != MemoryEffects::unknown ();
405425}
406426
407427namespace {
408428struct FnAttributeComparator {
409429 bool operator ()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
410- return compareFnAttributes (L, R, false );
430+ return compareFnAttributes (L, R);
411431 }
412432};
413433
414434struct AttributeComparator {
415435 bool operator ()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
416- // Order by argument attributes if function attributes are equal.
436+ // Order all intrinsics with no functiona attributes before all intrinsics
437+ // with function attributes.
438+ bool HasFnAttrLHS = hasFnAttributes (*L);
439+ bool HasFnAttrRHS = hasFnAttributes (*R);
440+
441+ // Order by argument attributes if function `hasFnAttributes` is equal.
417442 // This is reliable because each side is already sorted internally.
418- return compareFnAttributes (L, R,
419- L-> ArgumentAttributes < R->ArgumentAttributes );
443+ return std::tie (HasFnAttrLHS, L-> ArgumentAttributes ) <
444+ std::tie (HasFnAttrRHS, R->ArgumentAttributes );
420445 }
421446};
422447} // End anonymous namespace
423448
424- // / Returns the effective MemoryEffects for intrinsic \p Int.
425- static MemoryEffects getEffectiveME (const CodeGenIntrinsic &Int) {
426- MemoryEffects ME = Int.ME ;
427- // TODO: IntrHasSideEffects should affect not only readnone intrinsics.
428- if (ME.doesNotAccessMemory () && Int.hasSideEffects )
429- ME = MemoryEffects::unknown ();
430- return ME;
431- }
432-
433- // / Returns true if \p Int has a non-empty set of function attributes. Note that
434- // / NoUnwind = !canThrow, so we need to negate it's sense to test if the
435- // intrinsic has NoUnwind attribute.
436- static bool hasFnAttributes (const CodeGenIntrinsic &Int) {
437- return !Int.canThrow || Int.isNoReturn || Int.isNoCallback || Int.isNoSync ||
438- Int.isNoFree || Int.isWillReturn || Int.isCold || Int.isNoDuplicate ||
439- Int.isNoMerge || Int.isConvergent || Int.isSpeculatable ||
440- Int.isStrictFP || getEffectiveME (Int) != MemoryEffects::unknown ();
441- }
442-
443449// / Returns the name of the IR enum for argument attribute kind \p Kind.
444450static StringRef getArgAttrEnumName (CodeGenIntrinsic::ArgAttrKind Kind) {
445451 switch (Kind) {
@@ -576,75 +582,79 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) {
576582AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {
577583)" ;
578584
579- // Compute the maximum number of attribute arguments and the map.
580- typedef std::map<const CodeGenIntrinsic *, unsigned , AttributeComparator>
581- UniqAttrMapTy;
582- UniqAttrMapTy UniqAttributes;
583- unsigned MaxArgAttrs = 0 ;
584- unsigned AttrNum = 0 ;
585+ // Compute the maximum number of attribute arguments and the map. For function
586+ // attributes, we only consider whether the intrinsics has any function
587+ // arguments or not.
588+ std::map<const CodeGenIntrinsic *, unsigned , AttributeComparator>
589+ UniqAttributes;
585590 for (const CodeGenIntrinsic &Int : Ints) {
586- MaxArgAttrs =
587- std::max (MaxArgAttrs, unsigned (Int.ArgumentAttributes .size ()));
588- unsigned &N = UniqAttributes[&Int];
589- if (N)
590- continue ;
591- N = ++AttrNum;
592- assert (N < 65536 && " Too many unique attributes for table!" );
591+ unsigned ID = UniqAttributes.size ();
592+ UniqAttributes.try_emplace (&Int, ID);
593593 }
594594
595+ // Assign a 16-bit packed ID for each intrinsic. The lower 8-bits will be its
596+ // "argument attribute ID" (index in UniqAttributes) and upper 8 bits will be
597+ // its "function attribute ID" (index in UniqFnAttributes).
598+ if (UniqAttributes.size () > 256 )
599+ PrintFatalError (" Too many unique argument attributes for table!" );
600+ if (UniqFnAttributes.size () > 256 )
601+ PrintFatalError (" Too many unique function attributes for table!" );
602+
595603 // Emit an array of AttributeList. Most intrinsics will have at least one
596604 // entry, for the function itself (index ~1), which is usually nounwind.
597605 OS << " static constexpr uint16_t IntrinsicsToAttributesMap[] = {" ;
598- for (const CodeGenIntrinsic &Int : Ints)
599- OS << formatv (" \n {}, // {}" , UniqAttributes[&Int], Int.Name );
606+ for (const CodeGenIntrinsic &Int : Ints) {
607+ uint16_t FnAttrIndex = hasFnAttributes (Int) ? UniqFnAttributes[&Int] : 0 ;
608+ OS << formatv (" \n {} << 8 | {}, // {}" , FnAttrIndex,
609+ UniqAttributes[&Int], Int.Name );
610+ }
600611
601612 OS << formatv (R"(
602613 };
603- std::pair<unsigned, AttributeSet> AS[{}];
604- unsigned NumAttrs = 0;
605- if (id != 0) {{
606- switch(IntrinsicsToAttributesMap[id - 1]) {{
607- default: llvm_unreachable("Invalid attribute number");
608- )" ,
609- MaxArgAttrs + 1 );
614+ if (id == 0)
615+ return AttributeList();
616+
617+ uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
618+ uint8_t FnAttrID = PackedID >> 8;
619+ switch(PackedID & 0xFF) {{
620+ default: llvm_unreachable("Invalid attribute number");
621+ )" );
610622
611623 for (const auto [IntPtr, UniqueID] : UniqAttributes) {
612- OS << formatv (" case {}:\n " , UniqueID);
624+ OS << formatv (" case {}:\n " , UniqueID);
613625 const CodeGenIntrinsic &Int = *IntPtr;
614626
615627 // Keep track of the number of attributes we're writing out.
616- unsigned NumAttrs = 0 ;
628+ unsigned NumAttrs =
629+ llvm::count_if (Int.ArgumentAttributes ,
630+ [](const auto &Attrs) { return !Attrs.empty (); });
631+ NumAttrs += hasFnAttributes (Int);
632+ if (NumAttrs == 0 ) {
633+ OS << " return AttributeList();\n " ;
634+ continue ;
635+ }
617636
637+ OS << " return AttributeList::get(C, {\n " ;
638+ ListSeparator LS (" ,\n " );
618639 for (const auto &[AttrIdx, Attrs] : enumerate(Int.ArgumentAttributes )) {
619640 if (Attrs.empty ())
620641 continue ;
621642
622643 unsigned ArgAttrID = UniqArgAttributes.find (Attrs)->second ;
623- OS << formatv (
624- " AS[{}] = {{{ }, getIntrinsicArgAttributeSet(C, {})}; \n " ,
625- NumAttrs++, AttrIdx, ArgAttrID);
644+ OS << LS
645+ << formatv ( " {{{ }, getIntrinsicArgAttributeSet(C, {})}" , AttrIdx ,
646+ ArgAttrID);
626647 }
627648
628649 if (hasFnAttributes (Int)) {
629- unsigned FnAttrID = UniqFnAttributes.find (&Int)->second ;
630- OS << formatv (" AS[{}] = {{AttributeList::FunctionIndex, "
631- " getIntrinsicFnAttributeSet(C, {})};\n " ,
632- NumAttrs++, FnAttrID);
633- }
634-
635- if (NumAttrs) {
636- OS << formatv (R"( NumAttrs = {};
637- break;
638- )" ,
639- NumAttrs);
640- } else {
641- OS << " return AttributeList();\n " ;
650+ OS << LS
651+ << " {AttributeList::FunctionIndex, "
652+ " getIntrinsicFnAttributeSet(C, FnAttrID)}" ;
642653 }
654+ OS << " \n });\n " ;
643655 }
644656
645- OS << R"( }
646- }
647- return AttributeList::get(C, ArrayRef(AS, NumAttrs));
657+ OS << R"( }
648658}
649659#endif // GET_INTRINSIC_ATTRIBUTES
650660
0 commit comments