1//===- Attributes.cpp - Generate attributes -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Support/MemoryBuffer.h"
10#include "llvm/TableGen/Record.h"
11#include <algorithm>
12#include <string>
13#include <vector>
14using namespace llvm;
15
16#define DEBUG_TYPE "attr-enum"
17
18namespace {
19
20class Attributes {
21public:
22  Attributes(RecordKeeper &R) : Records(R) {}
23  void emit(raw_ostream &OS);
24
25private:
26  void emitTargetIndependentEnums(raw_ostream &OS);
27  void emitConversionFn(raw_ostream &OS);
28  void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
29
30  void printEnumAttrClasses(raw_ostream &OS,
31                            const std::vector<Record *> &Records);
32  void printStrBoolAttrClasses(raw_ostream &OS,
33                               const std::vector<Record *> &Records);
34
35  RecordKeeper &Records;
36};
37
38} // End anonymous namespace.
39
40void Attributes::emitTargetIndependentEnums(raw_ostream &OS) {
41  OS << "#ifdef GET_ATTR_ENUM\n";
42  OS << "#undef GET_ATTR_ENUM\n";
43
44  std::vector<Record*> Attrs =
45      Records.getAllDerivedDefinitions("EnumAttr");
46
47  for (auto A : Attrs)
48    OS << A->getName() << ",\n";
49
50  OS << "#endif\n";
51}
52
53void Attributes::emitConversionFn(raw_ostream &OS) {
54  OS << "#ifdef GET_ATTR_KIND_FROM_NAME\n";
55  OS << "#undef GET_ATTR_KIND_FROM_NAME\n";
56
57  std::vector<Record*> Attrs =
58      Records.getAllDerivedDefinitions("EnumAttr");
59
60  OS << "static Attribute::AttrKind getAttrKindFromName(StringRef AttrName) {\n";
61  OS << "  return StringSwitch<Attribute::AttrKind>(AttrName)\n";
62
63  for (auto A : Attrs) {
64    OS << "    .Case(\"" << A->getValueAsString("AttrString");
65    OS << "\", Attribute::" << A->getName() << ")\n";
66  }
67
68  OS << "    .Default(Attribute::None);\n";
69  OS << "}\n\n";
70
71  OS << "#endif\n";
72}
73
74void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
75  OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
76  OS << "#undef GET_ATTR_COMPAT_FUNC\n";
77
78  OS << "struct EnumAttr {\n";
79  OS << "  static bool isSet(const Function &Fn,\n";
80  OS << "                    Attribute::AttrKind Kind) {\n";
81  OS << "    return Fn.hasFnAttribute(Kind);\n";
82  OS << "  }\n\n";
83  OS << "  static void set(Function &Fn,\n";
84  OS << "                  Attribute::AttrKind Kind, bool Val) {\n";
85  OS << "    if (Val)\n";
86  OS << "      Fn.addFnAttr(Kind);\n";
87  OS << "    else\n";
88  OS << "      Fn.removeFnAttr(Kind);\n";
89  OS << "  }\n";
90  OS << "};\n\n";
91
92  OS << "struct StrBoolAttr {\n";
93  OS << "  static bool isSet(const Function &Fn,\n";
94  OS << "                    StringRef Kind) {\n";
95  OS << "    auto A = Fn.getFnAttribute(Kind);\n";
96  OS << "    return A.getValueAsString().equals(\"true\");\n";
97  OS << "  }\n\n";
98  OS << "  static void set(Function &Fn,\n";
99  OS << "                  StringRef Kind, bool Val) {\n";
100  OS << "    Fn.addFnAttr(Kind, Val ? \"true\" : \"false\");\n";
101  OS << "  }\n";
102  OS << "};\n\n";
103
104  printEnumAttrClasses(OS ,Records.getAllDerivedDefinitions("EnumAttr"));
105  printStrBoolAttrClasses(OS , Records.getAllDerivedDefinitions("StrBoolAttr"));
106
107  OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n"
108     << "                                        const Function &Callee) {\n";
109  OS << "  bool Ret = true;\n\n";
110
111  std::vector<Record *> CompatRules =
112      Records.getAllDerivedDefinitions("CompatRule");
113
114  for (auto *Rule : CompatRules) {
115    StringRef FuncName = Rule->getValueAsString("CompatFunc");
116    OS << "  Ret &= " << FuncName << "(Caller, Callee);\n";
117  }
118
119  OS << "\n";
120  OS << "  return Ret;\n";
121  OS << "}\n\n";
122
123  std::vector<Record *> MergeRules =
124      Records.getAllDerivedDefinitions("MergeRule");
125  OS << "static inline void mergeFnAttrs(Function &Caller,\n"
126     << "                                const Function &Callee) {\n";
127
128  for (auto *Rule : MergeRules) {
129    StringRef FuncName = Rule->getValueAsString("MergeFunc");
130    OS << "  " << FuncName << "(Caller, Callee);\n";
131  }
132
133  OS << "}\n\n";
134
135  OS << "#endif\n";
136}
137
138void Attributes::printEnumAttrClasses(raw_ostream &OS,
139                                      const std::vector<Record *> &Records) {
140  OS << "// EnumAttr classes\n";
141  for (const auto *R : Records) {
142    OS << "struct " << R->getName() << "Attr : EnumAttr {\n";
143    OS << "  static enum Attribute::AttrKind getKind() {\n";
144    OS << "    return llvm::Attribute::" << R->getName() << ";\n";
145    OS << "  }\n";
146    OS << "};\n";
147  }
148  OS << "\n";
149}
150
151void Attributes::printStrBoolAttrClasses(raw_ostream &OS,
152                                         const std::vector<Record *> &Records) {
153  OS << "// StrBoolAttr classes\n";
154  for (const auto *R : Records) {
155    OS << "struct " << R->getName() << "Attr : StrBoolAttr {\n";
156    OS << "  static StringRef getKind() {\n";
157    OS << "    return \"" << R->getValueAsString("AttrString") << "\";\n";
158    OS << "  }\n";
159    OS << "};\n";
160  }
161  OS << "\n";
162}
163
164void Attributes::emit(raw_ostream &OS) {
165  emitTargetIndependentEnums(OS);
166  emitConversionFn(OS);
167  emitFnAttrCompatCheck(OS, false);
168}
169
170namespace llvm {
171
172void EmitAttributes(RecordKeeper &RK, raw_ostream &OS) {
173  Attributes(RK).emit(OS);
174}
175
176} // End llvm namespace.
177