17d523365SDimitry Andric //===- Attributes.cpp - Generate attributes -------------------------------===//
27d523365SDimitry Andric //
37d523365SDimitry Andric //                     The LLVM Compiler Infrastructure
47d523365SDimitry Andric //
57d523365SDimitry Andric // This file is distributed under the University of Illinois Open Source
67d523365SDimitry Andric // License. See LICENSE.TXT for details.
77d523365SDimitry Andric //
87d523365SDimitry Andric //===----------------------------------------------------------------------===//
97d523365SDimitry Andric 
107d523365SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
117d523365SDimitry Andric #include "llvm/TableGen/Record.h"
127d523365SDimitry Andric #include <algorithm>
137d523365SDimitry Andric #include <string>
147d523365SDimitry Andric #include <vector>
157d523365SDimitry Andric using namespace llvm;
167d523365SDimitry Andric 
177d523365SDimitry Andric #define DEBUG_TYPE "attr-enum"
187d523365SDimitry Andric 
197d523365SDimitry Andric namespace {
207d523365SDimitry Andric 
217d523365SDimitry Andric class Attributes {
227d523365SDimitry Andric public:
Attributes(RecordKeeper & R)237d523365SDimitry Andric   Attributes(RecordKeeper &R) : Records(R) {}
247d523365SDimitry Andric   void emit(raw_ostream &OS);
257d523365SDimitry Andric 
267d523365SDimitry Andric private:
277d523365SDimitry Andric   void emitTargetIndependentEnums(raw_ostream &OS);
283ca95b02SDimitry Andric   void emitConversionFn(raw_ostream &OS);
297d523365SDimitry Andric   void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
307d523365SDimitry Andric 
317d523365SDimitry Andric   void printEnumAttrClasses(raw_ostream &OS,
327d523365SDimitry Andric                             const std::vector<Record *> &Records);
337d523365SDimitry Andric   void printStrBoolAttrClasses(raw_ostream &OS,
347d523365SDimitry Andric                                const std::vector<Record *> &Records);
357d523365SDimitry Andric 
367d523365SDimitry Andric   RecordKeeper &Records;
377d523365SDimitry Andric };
387d523365SDimitry Andric 
397d523365SDimitry Andric } // End anonymous namespace.
407d523365SDimitry Andric 
emitTargetIndependentEnums(raw_ostream & OS)417d523365SDimitry Andric void Attributes::emitTargetIndependentEnums(raw_ostream &OS) {
427d523365SDimitry Andric   OS << "#ifdef GET_ATTR_ENUM\n";
437d523365SDimitry Andric   OS << "#undef GET_ATTR_ENUM\n";
447d523365SDimitry Andric 
457d523365SDimitry Andric   std::vector<Record*> Attrs =
467d523365SDimitry Andric       Records.getAllDerivedDefinitions("EnumAttr");
477d523365SDimitry Andric 
487d523365SDimitry Andric   for (auto A : Attrs)
497d523365SDimitry Andric     OS << A->getName() << ",\n";
507d523365SDimitry Andric 
517d523365SDimitry Andric   OS << "#endif\n";
527d523365SDimitry Andric }
537d523365SDimitry Andric 
emitConversionFn(raw_ostream & OS)543ca95b02SDimitry Andric void Attributes::emitConversionFn(raw_ostream &OS) {
553ca95b02SDimitry Andric   OS << "#ifdef GET_ATTR_KIND_FROM_NAME\n";
563ca95b02SDimitry Andric   OS << "#undef GET_ATTR_KIND_FROM_NAME\n";
573ca95b02SDimitry Andric 
583ca95b02SDimitry Andric   std::vector<Record*> Attrs =
593ca95b02SDimitry Andric       Records.getAllDerivedDefinitions("EnumAttr");
603ca95b02SDimitry Andric 
613ca95b02SDimitry Andric   OS << "static Attribute::AttrKind getAttrKindFromName(StringRef AttrName) {\n";
623ca95b02SDimitry Andric   OS << "  return StringSwitch<Attribute::AttrKind>(AttrName)\n";
633ca95b02SDimitry Andric 
643ca95b02SDimitry Andric   for (auto A : Attrs) {
653ca95b02SDimitry Andric     OS << "    .Case(\"" << A->getValueAsString("AttrString");
663ca95b02SDimitry Andric     OS << "\", Attribute::" << A->getName() << ")\n";
673ca95b02SDimitry Andric   }
683ca95b02SDimitry Andric 
693ca95b02SDimitry Andric   OS << "    .Default(Attribute::None);\n";
703ca95b02SDimitry Andric   OS << "}\n\n";
713ca95b02SDimitry Andric 
723ca95b02SDimitry Andric   OS << "#endif\n";
733ca95b02SDimitry Andric }
743ca95b02SDimitry Andric 
emitFnAttrCompatCheck(raw_ostream & OS,bool IsStringAttr)757d523365SDimitry Andric void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
767d523365SDimitry Andric   OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
777d523365SDimitry Andric   OS << "#undef GET_ATTR_COMPAT_FUNC\n";
787d523365SDimitry Andric 
797d523365SDimitry Andric   OS << "struct EnumAttr {\n";
807d523365SDimitry Andric   OS << "  static bool isSet(const Function &Fn,\n";
817d523365SDimitry Andric   OS << "                    Attribute::AttrKind Kind) {\n";
827d523365SDimitry Andric   OS << "    return Fn.hasFnAttribute(Kind);\n";
837d523365SDimitry Andric   OS << "  }\n\n";
847d523365SDimitry Andric   OS << "  static void set(Function &Fn,\n";
857d523365SDimitry Andric   OS << "                  Attribute::AttrKind Kind, bool Val) {\n";
867d523365SDimitry Andric   OS << "    if (Val)\n";
877d523365SDimitry Andric   OS << "      Fn.addFnAttr(Kind);\n";
887d523365SDimitry Andric   OS << "    else\n";
897d523365SDimitry Andric   OS << "      Fn.removeFnAttr(Kind);\n";
907d523365SDimitry Andric   OS << "  }\n";
917d523365SDimitry Andric   OS << "};\n\n";
927d523365SDimitry Andric 
937d523365SDimitry Andric   OS << "struct StrBoolAttr {\n";
947d523365SDimitry Andric   OS << "  static bool isSet(const Function &Fn,\n";
957d523365SDimitry Andric   OS << "                    StringRef Kind) {\n";
967d523365SDimitry Andric   OS << "    auto A = Fn.getFnAttribute(Kind);\n";
977d523365SDimitry Andric   OS << "    return A.getValueAsString().equals(\"true\");\n";
987d523365SDimitry Andric   OS << "  }\n\n";
997d523365SDimitry Andric   OS << "  static void set(Function &Fn,\n";
1007d523365SDimitry Andric   OS << "                  StringRef Kind, bool Val) {\n";
1017d523365SDimitry Andric   OS << "    Fn.addFnAttr(Kind, Val ? \"true\" : \"false\");\n";
1027d523365SDimitry Andric   OS << "  }\n";
1037d523365SDimitry Andric   OS << "};\n\n";
1047d523365SDimitry Andric 
1057d523365SDimitry Andric   printEnumAttrClasses(OS ,Records.getAllDerivedDefinitions("EnumAttr"));
1067d523365SDimitry Andric   printStrBoolAttrClasses(OS , Records.getAllDerivedDefinitions("StrBoolAttr"));
1077d523365SDimitry Andric 
1087d523365SDimitry Andric   OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n"
1097d523365SDimitry Andric      << "                                        const Function &Callee) {\n";
1107d523365SDimitry Andric   OS << "  bool Ret = true;\n\n";
1117d523365SDimitry Andric 
1127d523365SDimitry Andric   std::vector<Record *> CompatRules =
1137d523365SDimitry Andric       Records.getAllDerivedDefinitions("CompatRule");
1147d523365SDimitry Andric 
1157d523365SDimitry Andric   for (auto *Rule : CompatRules) {
116*f9448bf3SDimitry Andric     StringRef FuncName = Rule->getValueAsString("CompatFunc");
1177d523365SDimitry Andric     OS << "  Ret &= " << FuncName << "(Caller, Callee);\n";
1187d523365SDimitry Andric   }
1197d523365SDimitry Andric 
1207d523365SDimitry Andric   OS << "\n";
1217d523365SDimitry Andric   OS << "  return Ret;\n";
1227d523365SDimitry Andric   OS << "}\n\n";
1237d523365SDimitry Andric 
1247d523365SDimitry Andric   std::vector<Record *> MergeRules =
1257d523365SDimitry Andric       Records.getAllDerivedDefinitions("MergeRule");
1267d523365SDimitry Andric   OS << "static inline void mergeFnAttrs(Function &Caller,\n"
1277d523365SDimitry Andric      << "                                const Function &Callee) {\n";
1287d523365SDimitry Andric 
1297d523365SDimitry Andric   for (auto *Rule : MergeRules) {
130*f9448bf3SDimitry Andric     StringRef FuncName = Rule->getValueAsString("MergeFunc");
1317d523365SDimitry Andric     OS << "  " << FuncName << "(Caller, Callee);\n";
1327d523365SDimitry Andric   }
1337d523365SDimitry Andric 
1347d523365SDimitry Andric   OS << "}\n\n";
1357d523365SDimitry Andric 
1367d523365SDimitry Andric   OS << "#endif\n";
1377d523365SDimitry Andric }
1387d523365SDimitry Andric 
printEnumAttrClasses(raw_ostream & OS,const std::vector<Record * > & Records)1397d523365SDimitry Andric void Attributes::printEnumAttrClasses(raw_ostream &OS,
1407d523365SDimitry Andric                                       const std::vector<Record *> &Records) {
1417d523365SDimitry Andric   OS << "// EnumAttr classes\n";
1427d523365SDimitry Andric   for (const auto *R : Records) {
1437d523365SDimitry Andric     OS << "struct " << R->getName() << "Attr : EnumAttr {\n";
1447d523365SDimitry Andric     OS << "  static enum Attribute::AttrKind getKind() {\n";
1457d523365SDimitry Andric     OS << "    return llvm::Attribute::" << R->getName() << ";\n";
1467d523365SDimitry Andric     OS << "  }\n";
1477d523365SDimitry Andric     OS << "};\n";
1487d523365SDimitry Andric   }
1497d523365SDimitry Andric   OS << "\n";
1507d523365SDimitry Andric }
1517d523365SDimitry Andric 
printStrBoolAttrClasses(raw_ostream & OS,const std::vector<Record * > & Records)1527d523365SDimitry Andric void Attributes::printStrBoolAttrClasses(raw_ostream &OS,
1537d523365SDimitry Andric                                          const std::vector<Record *> &Records) {
1547d523365SDimitry Andric   OS << "// StrBoolAttr classes\n";
1557d523365SDimitry Andric   for (const auto *R : Records) {
1567d523365SDimitry Andric     OS << "struct " << R->getName() << "Attr : StrBoolAttr {\n";
157d88c1a5aSDimitry Andric     OS << "  static StringRef getKind() {\n";
1587d523365SDimitry Andric     OS << "    return \"" << R->getValueAsString("AttrString") << "\";\n";
1597d523365SDimitry Andric     OS << "  }\n";
1607d523365SDimitry Andric     OS << "};\n";
1617d523365SDimitry Andric   }
1627d523365SDimitry Andric   OS << "\n";
1637d523365SDimitry Andric }
1647d523365SDimitry Andric 
emit(raw_ostream & OS)1657d523365SDimitry Andric void Attributes::emit(raw_ostream &OS) {
1667d523365SDimitry Andric   emitTargetIndependentEnums(OS);
1673ca95b02SDimitry Andric   emitConversionFn(OS);
1687d523365SDimitry Andric   emitFnAttrCompatCheck(OS, false);
1697d523365SDimitry Andric }
1707d523365SDimitry Andric 
1717d523365SDimitry Andric namespace llvm {
1727d523365SDimitry Andric 
EmitAttributes(RecordKeeper & RK,raw_ostream & OS)1737d523365SDimitry Andric void EmitAttributes(RecordKeeper &RK, raw_ostream &OS) {
1747d523365SDimitry Andric   Attributes(RK).emit(OS);
1757d523365SDimitry Andric }
1767d523365SDimitry Andric 
1777d523365SDimitry Andric } // End llvm namespace.
178