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>
14 using namespace llvm;
15 
16 #define DEBUG_TYPE "attr-enum"
17 
18 namespace {
19 
20 class Attributes {
21 public:
22   Attributes(RecordKeeper &R) : Records(R) {}
23   void emit(raw_ostream &OS);
24 
25 private:
26   void emitTargetIndependentNames(raw_ostream &OS);
27   void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
28 
29   RecordKeeper &Records;
30 };
31 
32 } // End anonymous namespace.
33 
34 void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
35   OS << "#ifdef GET_ATTR_NAMES\n";
36   OS << "#undef GET_ATTR_NAMES\n";
37 
38   OS << "#ifndef ATTRIBUTE_ALL\n";
39   OS << "#define ATTRIBUTE_ALL(FIRST, SECOND)\n";
40   OS << "#endif\n\n";
41 
42   auto Emit = [&](ArrayRef<StringRef> KindNames, StringRef MacroName) {
43     OS << "#ifndef " << MacroName << "\n";
44     OS << "#define " << MacroName
45        << "(FIRST, SECOND) ATTRIBUTE_ALL(FIRST, SECOND)\n";
46     OS << "#endif\n\n";
47     for (StringRef KindName : KindNames) {
48       for (auto A : Records.getAllDerivedDefinitions(KindName)) {
49         OS << MacroName << "(" << A->getName() << ","
50            << A->getValueAsString("AttrString") << ")\n";
51       }
52     }
53     OS << "#undef " << MacroName << "\n\n";
54   };
55 
56   // Emit attribute enums in the same order llvm::Attribute::operator< expects.
57   Emit({"EnumAttr", "TypeAttr", "IntAttr"}, "ATTRIBUTE_ENUM");
58   Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL");
59 
60   OS << "#undef ATTRIBUTE_ALL\n";
61   OS << "#endif\n\n";
62 
63   OS << "#ifdef GET_ATTR_ENUM\n";
64   OS << "#undef GET_ATTR_ENUM\n";
65   unsigned Value = 1; // Leave zero for AttrKind::None.
66   for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr"}) {
67     OS << "First" << KindName << " = " << Value << ",\n";
68     for (auto A : Records.getAllDerivedDefinitions(KindName)) {
69       OS << A->getName() << " = " << Value << ",\n";
70       Value++;
71     }
72     OS << "Last" << KindName << " = " << (Value - 1) << ",\n";
73   }
74   OS << "#endif\n\n";
75 }
76 
77 void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
78   OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
79   OS << "#undef GET_ATTR_COMPAT_FUNC\n";
80 
81   OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n"
82      << "                                        const Function &Callee) {\n";
83   OS << "  bool Ret = true;\n\n";
84 
85   std::vector<Record *> CompatRules =
86       Records.getAllDerivedDefinitions("CompatRule");
87 
88   for (auto *Rule : CompatRules) {
89     StringRef FuncName = Rule->getValueAsString("CompatFunc");
90     OS << "  Ret &= " << FuncName << "(Caller, Callee);\n";
91   }
92 
93   OS << "\n";
94   OS << "  return Ret;\n";
95   OS << "}\n\n";
96 
97   std::vector<Record *> MergeRules =
98       Records.getAllDerivedDefinitions("MergeRule");
99   OS << "static inline void mergeFnAttrs(Function &Caller,\n"
100      << "                                const Function &Callee) {\n";
101 
102   for (auto *Rule : MergeRules) {
103     StringRef FuncName = Rule->getValueAsString("MergeFunc");
104     OS << "  " << FuncName << "(Caller, Callee);\n";
105   }
106 
107   OS << "}\n\n";
108 
109   OS << "#endif\n";
110 }
111 
112 void Attributes::emit(raw_ostream &OS) {
113   emitTargetIndependentNames(OS);
114   emitFnAttrCompatCheck(OS, false);
115 }
116 
117 namespace llvm {
118 
119 void EmitAttributes(RecordKeeper &RK, raw_ostream &OS) {
120   Attributes(RK).emit(OS);
121 }
122 
123 } // End llvm namespace.
124