| //===- Attributes.cpp - Generate attributes -------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/TableGen/Error.h" | |
| #include "llvm/TableGen/Record.h" | |
| #include "llvm/TableGen/TableGenBackend.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "attr-enum" | |
| namespace { | |
| class Attributes { | |
| public: | |
| Attributes(const RecordKeeper &R) : Records(R) {} | |
| void run(raw_ostream &OS); | |
| private: | |
| void emitTargetIndependentNames(raw_ostream &OS); | |
| void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr); | |
| void emitAttributeProperties(raw_ostream &OF); | |
| const RecordKeeper &Records; | |
| }; | |
| } // End anonymous namespace. | |
| void Attributes::emitTargetIndependentNames(raw_ostream &OS) { | |
| OS << "#ifdef GET_ATTR_NAMES\n"; | |
| OS << "#undef GET_ATTR_NAMES\n"; | |
| auto Emit = [&](ArrayRef<StringRef> KindNames, StringRef MacroName) { | |
| OS << "#ifndef " << MacroName << "\n"; | |
| OS << "#define " << MacroName << "(FIRST, SECOND)\n"; | |
| OS << "#endif\n\n"; | |
| for (StringRef KindName : KindNames) { | |
| for (auto *A : Records.getAllDerivedDefinitions(KindName)) { | |
| OS << MacroName << "(" << A->getName() << "," | |
| << A->getValueAsString("AttrString") << ")\n"; | |
| } | |
| } | |
| OS << "#undef " << MacroName << "\n\n"; | |
| }; | |
| // Emit attribute enums in the same order llvm::Attribute::operator< expects. | |
| Emit({"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr", | |
| "ConstantRangeListAttr"}, | |
| "ATTRIBUTE_ENUM"); | |
| Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL"); | |
| OS << "#endif\n\n"; | |
| OS << "#ifdef GET_ATTR_ENUM\n"; | |
| OS << "#undef GET_ATTR_ENUM\n"; | |
| unsigned Value = 1; // Leave zero for AttrKind::None. | |
| for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr", | |
| "ConstantRangeAttr", "ConstantRangeListAttr"}) { | |
| OS << "First" << KindName << " = " << Value << ",\n"; | |
| for (auto *A : Records.getAllDerivedDefinitions(KindName)) { | |
| OS << A->getName() << " = " << Value << ",\n"; | |
| Value++; | |
| } | |
| OS << "Last" << KindName << " = " << (Value - 1) << ",\n"; | |
| } | |
| OS << "#endif\n\n"; | |
| } | |
| void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) { | |
| OS << "#ifdef GET_ATTR_COMPAT_FUNC\n"; | |
| OS << "#undef GET_ATTR_COMPAT_FUNC\n"; | |
| OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n" | |
| << " const Function &Callee) {\n"; | |
| OS << " bool Ret = true;\n\n"; | |
| for (const Record *Rule : Records.getAllDerivedDefinitions("CompatRule")) { | |
| StringRef FuncName = Rule->getValueAsString("CompatFunc"); | |
| OS << " Ret &= " << FuncName << "(Caller, Callee"; | |
| StringRef AttrName = Rule->getValueAsString("AttrName"); | |
| if (!AttrName.empty()) | |
| OS << ", \"" << AttrName << "\""; | |
| OS << ");\n"; | |
| } | |
| OS << "\n"; | |
| OS << " return Ret;\n"; | |
| OS << "}\n\n"; | |
| OS << "static inline void mergeFnAttrs(Function &Caller,\n" | |
| << " const Function &Callee) {\n"; | |
| for (const Record *Rule : Records.getAllDerivedDefinitions("MergeRule")) { | |
| StringRef FuncName = Rule->getValueAsString("MergeFunc"); | |
| OS << " " << FuncName << "(Caller, Callee);\n"; | |
| } | |
| OS << "}\n\n"; | |
| OS << "#endif\n"; | |
| } | |
| void Attributes::emitAttributeProperties(raw_ostream &OS) { | |
| OS << "#ifdef GET_ATTR_PROP_TABLE\n"; | |
| OS << "#undef GET_ATTR_PROP_TABLE\n"; | |
| OS << "static const uint8_t AttrPropTable[] = {\n"; | |
| for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr", | |
| "ConstantRangeAttr", "ConstantRangeListAttr"}) { | |
| bool AllowIntersectAnd = KindName == "EnumAttr"; | |
| bool AllowIntersectMin = KindName == "IntAttr"; | |
| for (auto *A : Records.getAllDerivedDefinitions(KindName)) { | |
| OS << "0"; | |
| for (const Init *P : *A->getValueAsListInit("Properties")) { | |
| if (!AllowIntersectAnd && | |
| cast<DefInit>(P)->getDef()->getName() == "IntersectAnd") | |
| PrintFatalError("'IntersectAnd' only compatible with 'EnumAttr'"); | |
| if (!AllowIntersectMin && | |
| cast<DefInit>(P)->getDef()->getName() == "IntersectMin") | |
| PrintFatalError("'IntersectMin' only compatible with 'IntAttr'"); | |
| OS << " | AttributeProperty::" << cast<DefInit>(P)->getDef()->getName(); | |
| } | |
| OS << ",\n"; | |
| } | |
| } | |
| OS << "};\n"; | |
| OS << "#endif\n"; | |
| } | |
| void Attributes::run(raw_ostream &OS) { | |
| emitTargetIndependentNames(OS); | |
| emitFnAttrCompatCheck(OS, false); | |
| emitAttributeProperties(OS); | |
| } | |
| static TableGen::Emitter::OptClass<Attributes> X("gen-attrs", | |
| "Generate attributes"); |