[llvm] 2a26a44 - [Attributes] Make intrinsic attribute generation more flexible (NFC)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 12 01:56:13 PDT 2022


Author: Nikita Popov
Date: 2022-10-12T10:56:01+02:00
New Revision: 2a26a445b342b0fa6090e8e99bf1fd0f18f6f7df

URL: https://github.com/llvm/llvm-project/commit/2a26a445b342b0fa6090e8e99bf1fd0f18f6f7df
DIFF: https://github.com/llvm/llvm-project/commit/2a26a445b342b0fa6090e8e99bf1fd0f18f6f7df.diff

LOG: [Attributes] Make intrinsic attribute generation more flexible (NFC)

Currently attributes for intrinsics are emitted using the
ArrayRef<AttrKind> based constructor for AttributeLists. This works
out fine for simple enum attributes, but doesn't really generalize
to attributes that accept values. We're already doing something
awkward for alignment attributes, and I'd like to have a cleaner
solution to this with
https://discourse.llvm.org/t/rfc-unify-memory-effect-attributes/65579 in mind.

The new generation approach is to instead directly construct
Attributes, giving us access to the full generality of that
interface. To avoid significantly increasing the size of the
generated code, we now also deduplicate the attribute sets. The
code generated per unique AttributeList looks like this:

  case 204: {
    AS[0] = {1, getIntrinsicArgAttributeSet(C, 5)};
    AS[1] = {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, 10)};
    NumAttrs = 2;
    break;
  }

and then the helper functions contain something like

  case 5:
    return AttributeSet::get(C, {
      Attribute::get(C, Attribute::NoCapture),
    });

and

  case 10:
    return AttributeSet::get(C, {
      Attribute::get(C, Attribute::NoUnwind),
      Attribute::get(C, Attribute::ArgMemOnly),
    });

A casualty of this change is the intrin-properties.td test, as I
don't think that FileCheck allows matching this kind of output.

Differential Revision: https://reviews.llvm.org/D135679

Added: 
    

Modified: 
    llvm/test/TableGen/intrin-side-effects.td
    llvm/utils/TableGen/CodeGenIntrinsics.h
    llvm/utils/TableGen/IntrinsicEmitter.cpp

Removed: 
    llvm/test/TableGen/intrin-properties.td


################################################################################
diff  --git a/llvm/test/TableGen/intrin-properties.td b/llvm/test/TableGen/intrin-properties.td
deleted file mode 100644
index 2e2e32d54fbff..0000000000000
--- a/llvm/test/TableGen/intrin-properties.td
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: sed -e 's/<PROP>/ArgMemOnly/;s/<ATTR>/ArgMemOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/Cold/;s/<ATTR>/Cold/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/Convergent/;s/<ATTR>/Convergent/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/InaccessibleMemOnly/;s/<ATTR>/InaccessibleMemOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/InaccessibleMemOrArgMemOnly/;s/<ATTR>/InaccessibleMemOrArgMemOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/NoDuplicate/;s/<ATTR>/NoDuplicate/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/NoFree/;s/<ATTR>/NoFree/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/NoMem/;s/<ATTR>/ReadNone/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/NoMerge/;s/<ATTR>/NoMerge/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/NoReturn/;s/<ATTR>/NoReturn/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/NoSync/;s/<ATTR>/NoSync/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/ReadMem/;s/<ATTR>/ReadOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/Speculatable/;s/<ATTR>/Speculatable/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/WillReturn/;s/<ATTR>/WillReturn/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-// RUN: sed -e 's/<PROP>/WriteMem/;s/<ATTR>/WriteOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t
-
-include "llvm/IR/Intrinsics.td"
-
-// CHECK: [[I:[0-9]+]], // llvm.tgtest.Intr<PROP>
-// CHECK: case [[I]]:
-// CHECK-NEXT: Atts[] = {{.*}}Attribute::<ATTR>
-def int_tgtest_Intr<PROP>:
-  Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [Intr<PROP>]>;
-

diff  --git a/llvm/test/TableGen/intrin-side-effects.td b/llvm/test/TableGen/intrin-side-effects.td
index 694fd6cdaf0ae..35b7dc9bd8fb4 100644
--- a/llvm/test/TableGen/intrin-side-effects.td
+++ b/llvm/test/TableGen/intrin-side-effects.td
@@ -40,6 +40,12 @@ class Intrinsic<list<LLVMType> ret_types,
 // ... this intrinsic.
 def int_random_gen   : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrHasSideEffects]>;
 
+// CHECK: static AttributeSet getIntrinsicFnAttributeSet(
+// CHECK: case 0:
+// CHECK-NEXT: return AttributeSet::get(C, {
+// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind),
+// CHECK-NEXT: });
+
 // CHECK: 1, // llvm.random.gen
 // CHECK: case 1:
-// CHECK-NEXT: Atts[] = {Attribute::NoUnwind}
+// CHECK-NEXT: AS[0] = {AttributeList::FunctionIndex, getIntrinsicFnAttributeSet(C, 0)};

diff  --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h
index 41e2365ec1209..5258b3afaf9c7 100644
--- a/llvm/utils/TableGen/CodeGenIntrinsics.h
+++ b/llvm/utils/TableGen/CodeGenIntrinsics.h
@@ -219,6 +219,8 @@ class CodeGenIntrinsicTable {
 
   bool empty() const { return Intrinsics.empty(); }
   size_t size() const { return Intrinsics.size(); }
+  auto begin() const { return Intrinsics.begin(); }
+  auto end() const { return Intrinsics.end(); }
   CodeGenIntrinsic &operator[](size_t Pos) { return Intrinsics[Pos]; }
   const CodeGenIntrinsic &operator[](size_t Pos) const {
     return Intrinsics[Pos];

diff  --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp
index a5685609d6f0a..ec3023f843db4 100644
--- a/llvm/utils/TableGen/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp
@@ -14,6 +14,7 @@
 #include "CodeGenTarget.h"
 #include "SequenceToOffsetTable.h"
 #include "TableGenBackends.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/TableGen/Error.h"
@@ -601,49 +602,64 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
 }
 
 namespace {
-struct AttributeComparator {
-  bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
-    // Sort throwing intrinsics after non-throwing intrinsics.
-    if (L->canThrow != R->canThrow)
-      return R->canThrow;
+Optional<bool> compareFnAttributes(const CodeGenIntrinsic *L,
+                                   const CodeGenIntrinsic *R) {
+  // Sort throwing intrinsics after non-throwing intrinsics.
+  if (L->canThrow != R->canThrow)
+    return R->canThrow;
+
+  if (L->isNoDuplicate != R->isNoDuplicate)
+    return R->isNoDuplicate;
+
+  if (L->isNoMerge != R->isNoMerge)
+    return R->isNoMerge;
 
-    if (L->isNoDuplicate != R->isNoDuplicate)
-      return R->isNoDuplicate;
+  if (L->isNoReturn != R->isNoReturn)
+    return R->isNoReturn;
 
-    if (L->isNoMerge != R->isNoMerge)
-      return R->isNoMerge;
+  if (L->isNoCallback != R->isNoCallback)
+    return R->isNoCallback;
 
-    if (L->isNoReturn != R->isNoReturn)
-      return R->isNoReturn;
+  if (L->isNoSync != R->isNoSync)
+    return R->isNoSync;
 
-    if (L->isNoCallback != R->isNoCallback)
-      return R->isNoCallback;
+  if (L->isNoFree != R->isNoFree)
+    return R->isNoFree;
 
-    if (L->isNoSync != R->isNoSync)
-      return R->isNoSync;
+  if (L->isWillReturn != R->isWillReturn)
+    return R->isWillReturn;
 
-    if (L->isNoFree != R->isNoFree)
-      return R->isNoFree;
+  if (L->isCold != R->isCold)
+    return R->isCold;
 
-    if (L->isWillReturn != R->isWillReturn)
-      return R->isWillReturn;
+  if (L->isConvergent != R->isConvergent)
+    return R->isConvergent;
 
-    if (L->isCold != R->isCold)
-      return R->isCold;
+  if (L->isSpeculatable != R->isSpeculatable)
+    return R->isSpeculatable;
 
-    if (L->isConvergent != R->isConvergent)
-      return R->isConvergent;
+  if (L->hasSideEffects != R->hasSideEffects)
+    return R->hasSideEffects;
 
-    if (L->isSpeculatable != R->isSpeculatable)
-      return R->isSpeculatable;
+  // Try to order by readonly/readnone attribute.
+  CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
+  CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
+  if (LK != RK) return (LK > RK);
 
-    if (L->hasSideEffects != R->hasSideEffects)
-      return R->hasSideEffects;
+  return None;
+}
+
+struct FnAttributeComparator {
+  bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
+    return compareFnAttributes(L, R).value_or(false);
+  }
+};
+
+struct AttributeComparator {
+  bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
+    if (Optional<bool> Res = compareFnAttributes(L, R))
+      return *Res;
 
-    // Try to order by readonly/readnone attribute.
-    CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
-    CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
-    if (LK != RK) return (LK > RK);
     // Order by argument attributes.
     // This is reliable because each side is already sorted internally.
     return (L->ArgumentAttributes < R->ArgumentAttributes);
@@ -656,6 +672,161 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
                                       raw_ostream &OS) {
   OS << "// Add parameter attributes that are not common to all intrinsics.\n";
   OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n";
+
+  // Compute unique argument attribute sets.
+  std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned>
+      UniqArgAttributes;
+  OS << "static AttributeSet getIntrinsicArgAttributeSet("
+     << "LLVMContext &C, unsigned ID) {\n"
+     << "  switch (ID) {\n"
+     << "  default: llvm_unreachable(\"Invalid attribute set number\");\n";
+  for (const CodeGenIntrinsic &Int : Ints) {
+    for (auto &Attrs : Int.ArgumentAttributes) {
+      if (Attrs.empty())
+        continue;
+
+      unsigned ID = UniqArgAttributes.size();
+      if (!UniqArgAttributes.try_emplace(Attrs, ID).second)
+        continue;
+
+      assert(is_sorted(Attrs) &&
+             "Argument attributes are not sorted");
+
+      OS << "  case " << ID << ":\n";
+      OS << "    return AttributeSet::get(C, {\n";
+      for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) {
+        switch (Attr.Kind) {
+        case CodeGenIntrinsic::NoCapture:
+          OS << "      Attribute::get(C, Attribute::NoCapture),\n";
+          break;
+        case CodeGenIntrinsic::NoAlias:
+          OS << "      Attribute::get(C, Attribute::NoAlias),\n";
+          break;
+        case CodeGenIntrinsic::NoUndef:
+          OS << "      Attribute::get(C, Attribute::NoUndef),\n";
+          break;
+        case CodeGenIntrinsic::NonNull:
+          OS << "      Attribute::get(C, Attribute::NonNull),\n";
+          break;
+        case CodeGenIntrinsic::Returned:
+          OS << "      Attribute::get(C, Attribute::Returned),\n";
+          break;
+        case CodeGenIntrinsic::ReadOnly:
+          OS << "      Attribute::get(C, Attribute::ReadOnly),\n";
+          break;
+        case CodeGenIntrinsic::WriteOnly:
+          OS << "      Attribute::get(C, Attribute::WriteOnly),\n";
+          break;
+        case CodeGenIntrinsic::ReadNone:
+          OS << "      Attribute::get(C, Attribute::ReadNone),\n";
+          break;
+        case CodeGenIntrinsic::ImmArg:
+          OS << "      Attribute::get(C, Attribute::ImmArg),\n";
+          break;
+        case CodeGenIntrinsic::Alignment:
+          OS << "      Attribute::get(C, Attribute::Alignment, "
+             << Attr.Value << "),\n";
+          break;
+        }
+      }
+      OS << "    });\n";
+    }
+  }
+  OS << "  }\n";
+  OS << "}\n\n";
+
+  // Compute unique function attribute sets.
+  std::map<const CodeGenIntrinsic*, unsigned, FnAttributeComparator>
+      UniqFnAttributes;
+  OS << "static AttributeSet getIntrinsicFnAttributeSet("
+     << "LLVMContext &C, unsigned ID) {\n"
+     << "  switch (ID) {\n"
+     << "  default: llvm_unreachable(\"Invalid attribute set number\");\n";
+  for (const CodeGenIntrinsic &Intrinsic : Ints) {
+    unsigned ID = UniqFnAttributes.size();
+    if (!UniqFnAttributes.try_emplace(&Intrinsic, ID).second)
+      continue;
+
+    OS << "  case " << ID << ":\n"
+       << "    return AttributeSet::get(C, {\n";
+    if (!Intrinsic.canThrow)
+      OS << "      Attribute::get(C, Attribute::NoUnwind),\n";
+    if (Intrinsic.isNoReturn)
+      OS << "      Attribute::get(C, Attribute::NoReturn),\n";
+    if (Intrinsic.isNoCallback)
+      OS << "      Attribute::get(C, Attribute::NoCallback),\n";
+    if (Intrinsic.isNoSync)
+      OS << "      Attribute::get(C, Attribute::NoSync),\n";
+    if (Intrinsic.isNoFree)
+      OS << "      Attribute::get(C, Attribute::NoFree),\n";
+    if (Intrinsic.isWillReturn)
+      OS << "      Attribute::get(C, Attribute::WillReturn),\n";
+    if (Intrinsic.isCold)
+      OS << "      Attribute::get(C, Attribute::Cold),\n";
+    if (Intrinsic.isNoDuplicate)
+      OS << "      Attribute::get(C, Attribute::NoDuplicate),\n";
+    if (Intrinsic.isNoMerge)
+      OS << "      Attribute::get(C, Attribute::NoMerge),\n";
+    if (Intrinsic.isConvergent)
+      OS << "      Attribute::get(C, Attribute::Convergent),\n";
+    if (Intrinsic.isSpeculatable)
+      OS << "      Attribute::get(C, Attribute::Speculatable),\n";
+
+    switch (Intrinsic.ModRef) {
+    case CodeGenIntrinsic::NoMem:
+      if (Intrinsic.hasSideEffects)
+        break;
+      OS << "      Attribute::get(C, Attribute::ReadNone),\n";
+      break;
+    case CodeGenIntrinsic::ReadArgMem:
+      OS << "      Attribute::get(C, Attribute::ReadOnly),\n";
+      OS << "      Attribute::get(C, Attribute::ArgMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadMem:
+      OS << "      Attribute::get(C, Attribute::ReadOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadInaccessibleMem:
+      OS << "      Attribute::get(C, Attribute::ReadOnly),\n";
+      OS << "      Attribute::get(C, Attribute::InaccessibleMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadInaccessibleMemOrArgMem:
+      OS << "      Attribute::get(C, Attribute::ReadOnly),\n";
+      OS << "      Attribute::get(C, "
+         << "Attribute::InaccessibleMemOrArgMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::WriteArgMem:
+      OS << "      Attribute::get(C, Attribute::WriteOnly),\n";
+      OS << "      Attribute::get(C, Attribute::ArgMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::WriteMem:
+      OS << "      Attribute::get(C, Attribute::WriteOnly),\n";
+      break;
+    case CodeGenIntrinsic::WriteInaccessibleMem:
+      OS << "      Attribute::get(C, Attribute::WriteOnly),\n";
+      OS << "      Attribute::get(C, Attribute::InaccessibleMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::WriteInaccessibleMemOrArgMem:
+      OS << "      Attribute::get(C, Attribute::WriteOnly),\n";
+      OS << "      Attribute::get(C, "
+         << "Attribute::InaccessibleMemOrArgMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadWriteArgMem:
+      OS << "      Attribute::get(C, Attribute::ArgMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadWriteInaccessibleMem:
+      OS << "      Attribute::get(C, Attribute::InaccessibleMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadWriteInaccessibleMemOrArgMem:
+      OS << "      Attribute::get(C, "
+         << "Attribute::InaccessibleMemOrArgMemOnly),\n";
+      break;
+    case CodeGenIntrinsic::ReadWriteMem:
+      break;
+    }
+    OS << "    });\n";
+  }
+  OS << "  }\n";
+  OS << "}\n\n";
   OS << "AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {\n";
 
   // Compute the maximum number of attribute arguments and the map
@@ -686,7 +857,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
   }
   OS << "  };\n\n";
 
-  OS << "  AttributeList AS[" << maxArgAttrs + 1 << "];\n";
+  OS << "  std::pair<unsigned, AttributeSet> AS[" << maxArgAttrs + 1 << "];\n";
   OS << "  unsigned NumAttrs = 0;\n";
   OS << "  if (id != 0) {\n";
   OS << "    switch(IntrinsicsToAttributesMap[id - 1]) {\n";
@@ -704,69 +875,9 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
       if (Attrs.empty())
         continue;
 
-      // The argument attributes are alreadys sorted by argument kind.
-      assert(is_sorted(Attrs) &&
-             "Argument attributes are not sorted");
-
-      OS << "      const Attribute::AttrKind AttrParam" << AttrIdx << "[] = {";
-      ListSeparator LS(",");
-      bool AllValuesAreZero = true;
-      SmallVector<uint64_t, 8> Values;
-      for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) {
-        switch (Attr.Kind) {
-        case CodeGenIntrinsic::NoCapture:
-          OS << LS << "Attribute::NoCapture";
-          break;
-        case CodeGenIntrinsic::NoAlias:
-          OS << LS << "Attribute::NoAlias";
-          break;
-        case CodeGenIntrinsic::NoUndef:
-          OS << LS << "Attribute::NoUndef";
-          break;
-        case CodeGenIntrinsic::NonNull:
-          OS << LS << "Attribute::NonNull";
-          break;
-        case CodeGenIntrinsic::Returned:
-          OS << LS << "Attribute::Returned";
-          break;
-        case CodeGenIntrinsic::ReadOnly:
-          OS << LS << "Attribute::ReadOnly";
-          break;
-        case CodeGenIntrinsic::WriteOnly:
-          OS << LS << "Attribute::WriteOnly";
-          break;
-        case CodeGenIntrinsic::ReadNone:
-          OS << LS << "Attribute::ReadNone";
-          break;
-        case CodeGenIntrinsic::ImmArg:
-          OS << LS << "Attribute::ImmArg";
-          break;
-        case CodeGenIntrinsic::Alignment:
-          OS << LS << "Attribute::Alignment";
-          break;
-        }
-
-        Values.push_back(Attr.Value);
-        AllValuesAreZero &= (Attr.Value == 0);
-      }
-
-      OS << "};\n";
-
-      // Generate attribute value array if not all attribute values are zero.
-      if (!AllValuesAreZero) {
-        OS << "      const uint64_t AttrValParam" << AttrIdx << "[]= {";
-        ListSeparator LSV(",");
-        for (const auto V : Values)
-          OS << LSV << V;
-        OS << "};\n";
-      }
-      // AttributeList::ReturnIndex = 0, AttrParam0 corresponds to return
-      // value.
-      OS << "      AS[" << numAttrs++ << "] = AttributeList::get(C, "
-         << AttrIdx << ", AttrParam" << AttrIdx;
-      if (!AllValuesAreZero)
-        OS << ", AttrValParam" << AttrIdx;
-      OS << ");\n";
+      unsigned ID = UniqArgAttributes.find(Attrs)->second;
+      OS << "      AS[" << numAttrs++ << "] = {" << AttrIdx
+         << ", getIntrinsicArgAttributeSet(C, " << ID << ")};\n";
     }
 
     if (!Intrinsic.canThrow ||
@@ -776,103 +887,18 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
         Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold ||
         Intrinsic.isNoDuplicate || Intrinsic.isNoMerge ||
         Intrinsic.isConvergent || Intrinsic.isSpeculatable) {
-      OS << "      const Attribute::AttrKind Atts[] = {";
-      ListSeparator LS(",");
-      if (!Intrinsic.canThrow)
-        OS << LS << "Attribute::NoUnwind";
-      if (Intrinsic.isNoReturn)
-        OS << LS << "Attribute::NoReturn";
-      if (Intrinsic.isNoCallback)
-        OS << LS << "Attribute::NoCallback";
-      if (Intrinsic.isNoSync)
-        OS << LS << "Attribute::NoSync";
-      if (Intrinsic.isNoFree)
-        OS << LS << "Attribute::NoFree";
-      if (Intrinsic.isWillReturn)
-        OS << LS << "Attribute::WillReturn";
-      if (Intrinsic.isCold)
-        OS << LS << "Attribute::Cold";
-      if (Intrinsic.isNoDuplicate)
-        OS << LS << "Attribute::NoDuplicate";
-      if (Intrinsic.isNoMerge)
-        OS << LS << "Attribute::NoMerge";
-      if (Intrinsic.isConvergent)
-        OS << LS << "Attribute::Convergent";
-      if (Intrinsic.isSpeculatable)
-        OS << LS << "Attribute::Speculatable";
-
-      switch (Intrinsic.ModRef) {
-      case CodeGenIntrinsic::NoMem:
-        if (Intrinsic.hasSideEffects)
-          break;
-        OS << LS;
-        OS << "Attribute::ReadNone";
-        break;
-      case CodeGenIntrinsic::ReadArgMem:
-        OS << LS;
-        OS << "Attribute::ReadOnly,";
-        OS << "Attribute::ArgMemOnly";
-        break;
-      case CodeGenIntrinsic::ReadMem:
-        OS << LS;
-        OS << "Attribute::ReadOnly";
-        break;
-      case CodeGenIntrinsic::ReadInaccessibleMem:
-        OS << LS;
-        OS << "Attribute::ReadOnly,";
-        OS << "Attribute::InaccessibleMemOnly";
-        break;
-      case CodeGenIntrinsic::ReadInaccessibleMemOrArgMem:
-        OS << LS;
-        OS << "Attribute::ReadOnly,";
-        OS << "Attribute::InaccessibleMemOrArgMemOnly";
-        break;
-      case CodeGenIntrinsic::WriteArgMem:
-        OS << LS;
-        OS << "Attribute::WriteOnly,";
-        OS << "Attribute::ArgMemOnly";
-        break;
-      case CodeGenIntrinsic::WriteMem:
-        OS << LS;
-        OS << "Attribute::WriteOnly";
-        break;
-      case CodeGenIntrinsic::WriteInaccessibleMem:
-        OS << LS;
-        OS << "Attribute::WriteOnly,";
-        OS << "Attribute::InaccessibleMemOnly";
-        break;
-      case CodeGenIntrinsic::WriteInaccessibleMemOrArgMem:
-        OS << LS;
-        OS << "Attribute::WriteOnly,";
-        OS << "Attribute::InaccessibleMemOrArgMemOnly";
-        break;
-      case CodeGenIntrinsic::ReadWriteArgMem:
-        OS << LS;
-        OS << "Attribute::ArgMemOnly";
-        break;
-      case CodeGenIntrinsic::ReadWriteInaccessibleMem:
-        OS << LS;
-        OS << "Attribute::InaccessibleMemOnly";
-        break;
-      case CodeGenIntrinsic::ReadWriteInaccessibleMemOrArgMem:
-        OS << LS;
-        OS << "Attribute::InaccessibleMemOrArgMemOnly";
-        break;
-      case CodeGenIntrinsic::ReadWriteMem:
-        break;
-      }
-      OS << "};\n";
-      OS << "      AS[" << numAttrs++ << "] = AttributeList::get(C, "
-         << "AttributeList::FunctionIndex, Atts);\n";
+      unsigned ID = UniqFnAttributes.find(&Intrinsic)->second;
+      OS << "      AS[" << numAttrs++ << "] = {AttributeList::FunctionIndex, "
+         << "getIntrinsicFnAttributeSet(C, " << ID << ")};\n";
     }
 
     if (numAttrs) {
       OS << "      NumAttrs = " << numAttrs << ";\n";
       OS << "      break;\n";
-      OS << "      }\n";
+      OS << "    }\n";
     } else {
       OS << "      return AttributeList();\n";
-      OS << "      }\n";
+      OS << "    }\n";
     }
   }
 


        


More information about the llvm-commits mailing list