#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"
}
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);
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
}
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";
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 ||
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";
}
}