29
29
#include < array>
30
30
#include < cassert>
31
31
#include < cctype>
32
+ #include < limits>
32
33
#include < map>
33
34
#include < optional>
34
35
#include < string>
@@ -379,8 +380,17 @@ static constexpr {} IIT_Table[] = {{
379
380
OS << " #endif\n\n " ; // End of GET_INTRINSIC_GENERATOR_GLOBAL
380
381
}
381
382
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
+
382
392
static bool compareFnAttributes (const CodeGenIntrinsic *L,
383
- const CodeGenIntrinsic *R, bool Default ) {
393
+ const CodeGenIntrinsic *R) {
384
394
auto TieBoolAttributes = [](const CodeGenIntrinsic *I) -> auto {
385
395
// Sort throwing intrinsics after non-throwing intrinsics.
386
396
return std::tie (I->canThrow , I->isNoDuplicate , I->isNoMerge , I->isNoReturn ,
@@ -396,50 +406,46 @@ static bool compareFnAttributes(const CodeGenIntrinsic *L,
396
406
return TieL < TieR;
397
407
398
408
// 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 ();
401
411
if (LME != RME)
402
412
return LME > RME;
403
413
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 ();
405
425
}
406
426
407
427
namespace {
408
428
struct FnAttributeComparator {
409
429
bool operator ()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
410
- return compareFnAttributes (L, R, false );
430
+ return compareFnAttributes (L, R);
411
431
}
412
432
};
413
433
414
434
struct AttributeComparator {
415
435
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.
417
442
// 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 );
420
445
}
421
446
};
422
447
} // End anonymous namespace
423
448
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
-
443
449
// / Returns the name of the IR enum for argument attribute kind \p Kind.
444
450
static StringRef getArgAttrEnumName (CodeGenIntrinsic::ArgAttrKind Kind) {
445
451
switch (Kind) {
@@ -576,75 +582,79 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) {
576
582
AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {
577
583
)" ;
578
584
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;
585
590
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);
593
593
}
594
594
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
+
595
603
// Emit an array of AttributeList. Most intrinsics will have at least one
596
604
// entry, for the function itself (index ~1), which is usually nounwind.
597
605
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
+ }
600
611
601
612
OS << formatv (R"(
602
613
};
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
+ )" );
610
622
611
623
for (const auto [IntPtr, UniqueID ] : UniqAttributes) {
612
- OS << formatv (" case {}:\n " , UniqueID );
624
+ OS << formatv (" case {}:\n " , UniqueID );
613
625
const CodeGenIntrinsic &Int = *IntPtr;
614
626
615
627
// 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
+ }
617
636
637
+ OS << " return AttributeList::get(C, {\n " ;
638
+ ListSeparator LS (" ,\n " );
618
639
for (const auto &[AttrIdx, Attrs] : enumerate(Int.ArgumentAttributes )) {
619
640
if (Attrs.empty ())
620
641
continue ;
621
642
622
643
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);
626
647
}
627
648
628
649
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)}" ;
642
653
}
654
+ OS << " \n });\n " ;
643
655
}
644
656
645
- OS << R"( }
646
- }
647
- return AttributeList::get(C, ArrayRef(AS, NumAttrs));
657
+ OS << R"( }
648
658
}
649
659
#endif // GET_INTRINSIC_ATTRIBUTES
650
660
0 commit comments