diff --git a/llvm/test/TableGen/intrin-properties.td b/llvm/test/TableGen/intrin-properties.td deleted file mode 100644 --- a/llvm/test/TableGen/intrin-properties.td +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: sed -e 's//ArgMemOnly/;s//ArgMemOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//Cold/;s//Cold/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//Convergent/;s//Convergent/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//InaccessibleMemOnly/;s//InaccessibleMemOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//InaccessibleMemOrArgMemOnly/;s//InaccessibleMemOrArgMemOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//NoDuplicate/;s//NoDuplicate/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//NoFree/;s//NoFree/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//NoMem/;s//ReadNone/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//NoMerge/;s//NoMerge/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//NoReturn/;s//NoReturn/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//NoSync/;s//NoSync/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//ReadMem/;s//ReadOnly/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//Speculatable/;s//Speculatable/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//WillReturn/;s//WillReturn/' < %s > %t; llvm-tblgen -gen-intrinsic-impl -I %p/../../include %t | FileCheck %t -// RUN: sed -e 's//WriteMem/;s//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 -// CHECK: case [[I]]: -// CHECK-NEXT: Atts[] = {{.*}}Attribute:: -def int_tgtest_Intr: - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [Intr]>; - diff --git a/llvm/test/TableGen/intrin-side-effects.td b/llvm/test/TableGen/intrin-side-effects.td --- a/llvm/test/TableGen/intrin-side-effects.td +++ b/llvm/test/TableGen/intrin-side-effects.td @@ -40,6 +40,12 @@ // ... 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 --- a/llvm/utils/TableGen/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/CodeGenIntrinsics.h @@ -219,6 +219,8 @@ 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 --- 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 @@ } 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 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 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 @@ 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, 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 + 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 @@ } OS << " };\n\n"; - OS << " AttributeList AS[" << maxArgAttrs + 1 << "];\n"; + OS << " std::pair AS[" << maxArgAttrs + 1 << "];\n"; OS << " unsigned NumAttrs = 0;\n"; OS << " if (id != 0) {\n"; OS << " switch(IntrinsicsToAttributesMap[id - 1]) {\n"; @@ -704,69 +875,9 @@ 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 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 @@ 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"; } }