xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===- IntrinsicEmitter.cpp - Generate intrinsic information --------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This tablegen backend emits information about intrinsic functions.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "CodeGenIntrinsics.h"
14*700637cbSDimitry Andric #include "SequenceToOffsetTable.h"
15*700637cbSDimitry Andric #include "llvm/ADT/STLExtras.h"
16*700637cbSDimitry Andric #include "llvm/ADT/SmallVector.h"
17*700637cbSDimitry Andric #include "llvm/ADT/StringRef.h"
18*700637cbSDimitry Andric #include "llvm/ADT/Twine.h"
19*700637cbSDimitry Andric #include "llvm/Support/CommandLine.h"
20*700637cbSDimitry Andric #include "llvm/Support/ErrorHandling.h"
21*700637cbSDimitry Andric #include "llvm/Support/FormatVariadic.h"
22*700637cbSDimitry Andric #include "llvm/Support/ModRef.h"
23*700637cbSDimitry Andric #include "llvm/Support/raw_ostream.h"
24*700637cbSDimitry Andric #include "llvm/TableGen/Error.h"
25*700637cbSDimitry Andric #include "llvm/TableGen/Record.h"
26*700637cbSDimitry Andric #include "llvm/TableGen/StringToOffsetTable.h"
27*700637cbSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
28*700637cbSDimitry Andric #include <algorithm>
29*700637cbSDimitry Andric #include <array>
30*700637cbSDimitry Andric #include <cassert>
31*700637cbSDimitry Andric #include <cctype>
32*700637cbSDimitry Andric #include <map>
33*700637cbSDimitry Andric #include <optional>
34*700637cbSDimitry Andric #include <string>
35*700637cbSDimitry Andric #include <utility>
36*700637cbSDimitry Andric #include <vector>
37*700637cbSDimitry Andric using namespace llvm;
38*700637cbSDimitry Andric 
39*700637cbSDimitry Andric static cl::OptionCategory GenIntrinsicCat("Options for -gen-intrinsic-enums");
40*700637cbSDimitry Andric static cl::opt<std::string>
41*700637cbSDimitry Andric     IntrinsicPrefix("intrinsic-prefix",
42*700637cbSDimitry Andric                     cl::desc("Generate intrinsics with this target prefix"),
43*700637cbSDimitry Andric                     cl::value_desc("target prefix"), cl::cat(GenIntrinsicCat));
44*700637cbSDimitry Andric 
45*700637cbSDimitry Andric namespace {
46*700637cbSDimitry Andric class IntrinsicEmitter {
47*700637cbSDimitry Andric   const RecordKeeper &Records;
48*700637cbSDimitry Andric 
49*700637cbSDimitry Andric public:
IntrinsicEmitter(const RecordKeeper & R)50*700637cbSDimitry Andric   IntrinsicEmitter(const RecordKeeper &R) : Records(R) {}
51*700637cbSDimitry Andric 
52*700637cbSDimitry Andric   void run(raw_ostream &OS, bool Enums);
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric   void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
55*700637cbSDimitry Andric   void EmitArgKind(raw_ostream &OS);
56*700637cbSDimitry Andric   void EmitIITInfo(raw_ostream &OS);
57*700637cbSDimitry Andric   void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
58*700637cbSDimitry Andric   void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints,
59*700637cbSDimitry Andric                                 raw_ostream &OS);
60*700637cbSDimitry Andric   void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints,
61*700637cbSDimitry Andric                                     raw_ostream &OS);
62*700637cbSDimitry Andric   void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
63*700637cbSDimitry Andric   void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
64*700637cbSDimitry Andric   void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,
65*700637cbSDimitry Andric                                  bool IsClang, raw_ostream &OS);
66*700637cbSDimitry Andric };
67*700637cbSDimitry Andric 
68*700637cbSDimitry Andric // Helper class to use with `TableGen::Emitter::OptClass`.
69*700637cbSDimitry Andric template <bool Enums> class IntrinsicEmitterOpt : public IntrinsicEmitter {
70*700637cbSDimitry Andric public:
IntrinsicEmitterOpt(const RecordKeeper & R)71*700637cbSDimitry Andric   IntrinsicEmitterOpt(const RecordKeeper &R) : IntrinsicEmitter(R) {}
run(raw_ostream & OS)72*700637cbSDimitry Andric   void run(raw_ostream &OS) { IntrinsicEmitter::run(OS, Enums); }
73*700637cbSDimitry Andric };
74*700637cbSDimitry Andric 
75*700637cbSDimitry Andric } // End anonymous namespace
76*700637cbSDimitry Andric 
77*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
78*700637cbSDimitry Andric // IntrinsicEmitter Implementation
79*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
80*700637cbSDimitry Andric 
run(raw_ostream & OS,bool Enums)81*700637cbSDimitry Andric void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) {
82*700637cbSDimitry Andric   emitSourceFileHeader("Intrinsic Function Source Fragment", OS);
83*700637cbSDimitry Andric 
84*700637cbSDimitry Andric   CodeGenIntrinsicTable Ints(Records);
85*700637cbSDimitry Andric 
86*700637cbSDimitry Andric   if (Enums) {
87*700637cbSDimitry Andric     // Emit the enum information.
88*700637cbSDimitry Andric     EmitEnumInfo(Ints, OS);
89*700637cbSDimitry Andric 
90*700637cbSDimitry Andric     // Emit ArgKind for Intrinsics.h.
91*700637cbSDimitry Andric     EmitArgKind(OS);
92*700637cbSDimitry Andric   } else {
93*700637cbSDimitry Andric     // Emit IIT_Info constants.
94*700637cbSDimitry Andric     EmitIITInfo(OS);
95*700637cbSDimitry Andric 
96*700637cbSDimitry Andric     // Emit the target metadata.
97*700637cbSDimitry Andric     EmitTargetInfo(Ints, OS);
98*700637cbSDimitry Andric 
99*700637cbSDimitry Andric     // Emit the intrinsic ID -> name table.
100*700637cbSDimitry Andric     EmitIntrinsicToNameTable(Ints, OS);
101*700637cbSDimitry Andric 
102*700637cbSDimitry Andric     // Emit the intrinsic ID -> overload table.
103*700637cbSDimitry Andric     EmitIntrinsicToOverloadTable(Ints, OS);
104*700637cbSDimitry Andric 
105*700637cbSDimitry Andric     // Emit the intrinsic declaration generator.
106*700637cbSDimitry Andric     EmitGenerator(Ints, OS);
107*700637cbSDimitry Andric 
108*700637cbSDimitry Andric     // Emit the intrinsic parameter attributes.
109*700637cbSDimitry Andric     EmitAttributes(Ints, OS);
110*700637cbSDimitry Andric 
111*700637cbSDimitry Andric     // Emit code to translate Clang builtins into LLVM intrinsics.
112*700637cbSDimitry Andric     EmitIntrinsicToBuiltinMap(Ints, true, OS);
113*700637cbSDimitry Andric 
114*700637cbSDimitry Andric     // Emit code to translate MS builtins into LLVM intrinsics.
115*700637cbSDimitry Andric     EmitIntrinsicToBuiltinMap(Ints, false, OS);
116*700637cbSDimitry Andric   }
117*700637cbSDimitry Andric }
118*700637cbSDimitry Andric 
EmitEnumInfo(const CodeGenIntrinsicTable & Ints,raw_ostream & OS)119*700637cbSDimitry Andric void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,
120*700637cbSDimitry Andric                                     raw_ostream &OS) {
121*700637cbSDimitry Andric   // Find the TargetSet for which to generate enums. There will be an initial
122*700637cbSDimitry Andric   // set with an empty target prefix which will include target independent
123*700637cbSDimitry Andric   // intrinsics like dbg.value.
124*700637cbSDimitry Andric   using TargetSet = CodeGenIntrinsicTable::TargetSet;
125*700637cbSDimitry Andric   const TargetSet *Set = nullptr;
126*700637cbSDimitry Andric   for (const auto &Target : Ints.getTargets()) {
127*700637cbSDimitry Andric     if (Target.Name == IntrinsicPrefix) {
128*700637cbSDimitry Andric       Set = &Target;
129*700637cbSDimitry Andric       break;
130*700637cbSDimitry Andric     }
131*700637cbSDimitry Andric   }
132*700637cbSDimitry Andric   if (!Set) {
133*700637cbSDimitry Andric     // The first entry is for target independent intrinsics, so drop it.
134*700637cbSDimitry Andric     auto KnowTargets = Ints.getTargets().drop_front();
135*700637cbSDimitry Andric     PrintFatalError([KnowTargets](raw_ostream &OS) {
136*700637cbSDimitry Andric       OS << "tried to generate intrinsics for unknown target "
137*700637cbSDimitry Andric          << IntrinsicPrefix << "\nKnown targets are: ";
138*700637cbSDimitry Andric       interleaveComma(KnowTargets, OS,
139*700637cbSDimitry Andric                       [&OS](const TargetSet &Target) { OS << Target.Name; });
140*700637cbSDimitry Andric       OS << '\n';
141*700637cbSDimitry Andric     });
142*700637cbSDimitry Andric   }
143*700637cbSDimitry Andric 
144*700637cbSDimitry Andric   // Generate a complete header for target specific intrinsics.
145*700637cbSDimitry Andric   if (IntrinsicPrefix.empty()) {
146*700637cbSDimitry Andric     OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n";
147*700637cbSDimitry Andric   } else {
148*700637cbSDimitry Andric     std::string UpperPrefix = StringRef(IntrinsicPrefix).upper();
149*700637cbSDimitry Andric     OS << formatv("#ifndef LLVM_IR_INTRINSIC_{}_ENUMS_H\n", UpperPrefix);
150*700637cbSDimitry Andric     OS << formatv("#define LLVM_IR_INTRINSIC_{}_ENUMS_H\n", UpperPrefix);
151*700637cbSDimitry Andric     OS << "namespace llvm::Intrinsic {\n";
152*700637cbSDimitry Andric     OS << formatv("enum {}Intrinsics : unsigned {{\n", UpperPrefix);
153*700637cbSDimitry Andric   }
154*700637cbSDimitry Andric 
155*700637cbSDimitry Andric   OS << "// Enum values for intrinsics.\n";
156*700637cbSDimitry Andric   bool First = true;
157*700637cbSDimitry Andric   for (const auto &Int : Ints[*Set]) {
158*700637cbSDimitry Andric     OS << "    " << Int.EnumName;
159*700637cbSDimitry Andric 
160*700637cbSDimitry Andric     // Assign a value to the first intrinsic in this target set so that all
161*700637cbSDimitry Andric     // intrinsic ids are distinct.
162*700637cbSDimitry Andric     if (First) {
163*700637cbSDimitry Andric       OS << " = " << Set->Offset + 1;
164*700637cbSDimitry Andric       First = false;
165*700637cbSDimitry Andric     }
166*700637cbSDimitry Andric 
167*700637cbSDimitry Andric     OS << ", ";
168*700637cbSDimitry Andric     if (Int.EnumName.size() < 40)
169*700637cbSDimitry Andric       OS.indent(40 - Int.EnumName.size());
170*700637cbSDimitry Andric     OS << formatv(" // {}\n", Int.Name);
171*700637cbSDimitry Andric   }
172*700637cbSDimitry Andric 
173*700637cbSDimitry Andric   // Emit num_intrinsics into the target neutral enum.
174*700637cbSDimitry Andric   if (IntrinsicPrefix.empty()) {
175*700637cbSDimitry Andric     OS << formatv("    num_intrinsics = {}\n", Ints.size() + 1);
176*700637cbSDimitry Andric     OS << "#endif\n\n";
177*700637cbSDimitry Andric   } else {
178*700637cbSDimitry Andric     OS << R"(}; // enum
179*700637cbSDimitry Andric } // namespace llvm::Intrinsic
180*700637cbSDimitry Andric #endif
181*700637cbSDimitry Andric 
182*700637cbSDimitry Andric )";
183*700637cbSDimitry Andric   }
184*700637cbSDimitry Andric }
185*700637cbSDimitry Andric 
EmitArgKind(raw_ostream & OS)186*700637cbSDimitry Andric void IntrinsicEmitter::EmitArgKind(raw_ostream &OS) {
187*700637cbSDimitry Andric   if (!IntrinsicPrefix.empty())
188*700637cbSDimitry Andric     return;
189*700637cbSDimitry Andric   OS << "// llvm::Intrinsic::IITDescriptor::ArgKind.\n";
190*700637cbSDimitry Andric   OS << "#ifdef GET_INTRINSIC_ARGKIND\n";
191*700637cbSDimitry Andric   if (const auto RecArgKind = Records.getDef("ArgKind")) {
192*700637cbSDimitry Andric     for (const auto &RV : RecArgKind->getValues())
193*700637cbSDimitry Andric       OS << "    AK_" << RV.getName() << " = " << *RV.getValue() << ",\n";
194*700637cbSDimitry Andric   } else {
195*700637cbSDimitry Andric     OS << "#error \"ArgKind is not defined\"\n";
196*700637cbSDimitry Andric   }
197*700637cbSDimitry Andric   OS << "#endif\n\n";
198*700637cbSDimitry Andric }
199*700637cbSDimitry Andric 
EmitIITInfo(raw_ostream & OS)200*700637cbSDimitry Andric void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) {
201*700637cbSDimitry Andric   OS << "#ifdef GET_INTRINSIC_IITINFO\n";
202*700637cbSDimitry Andric   std::array<StringRef, 256> RecsByNumber;
203*700637cbSDimitry Andric   auto IIT_Base = Records.getAllDerivedDefinitionsIfDefined("IIT_Base");
204*700637cbSDimitry Andric   for (const Record *Rec : IIT_Base) {
205*700637cbSDimitry Andric     auto Number = Rec->getValueAsInt("Number");
206*700637cbSDimitry Andric     assert(0 <= Number && Number < (int)RecsByNumber.size() &&
207*700637cbSDimitry Andric            "IIT_Info.Number should be uint8_t");
208*700637cbSDimitry Andric     assert(RecsByNumber[Number].empty() && "Duplicate IIT_Info.Number");
209*700637cbSDimitry Andric     RecsByNumber[Number] = Rec->getName();
210*700637cbSDimitry Andric   }
211*700637cbSDimitry Andric   if (IIT_Base.size() > 0) {
212*700637cbSDimitry Andric     for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I)
213*700637cbSDimitry Andric       if (!RecsByNumber[I].empty())
214*700637cbSDimitry Andric         OS << "  " << RecsByNumber[I] << " = " << I << ",\n";
215*700637cbSDimitry Andric   } else {
216*700637cbSDimitry Andric     OS << "#error \"class IIT_Base is not defined\"\n";
217*700637cbSDimitry Andric   }
218*700637cbSDimitry Andric   OS << "#endif\n\n";
219*700637cbSDimitry Andric }
220*700637cbSDimitry Andric 
EmitTargetInfo(const CodeGenIntrinsicTable & Ints,raw_ostream & OS)221*700637cbSDimitry Andric void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints,
222*700637cbSDimitry Andric                                       raw_ostream &OS) {
223*700637cbSDimitry Andric   OS << R"(// Target mapping.
224*700637cbSDimitry Andric #ifdef GET_INTRINSIC_TARGET_DATA
225*700637cbSDimitry Andric struct IntrinsicTargetInfo {
226*700637cbSDimitry Andric   StringLiteral Name;
227*700637cbSDimitry Andric   size_t Offset;
228*700637cbSDimitry Andric   size_t Count;
229*700637cbSDimitry Andric };
230*700637cbSDimitry Andric static constexpr IntrinsicTargetInfo TargetInfos[] = {
231*700637cbSDimitry Andric )";
232*700637cbSDimitry Andric   for (const auto [Name, Offset, Count] : Ints.getTargets())
233*700637cbSDimitry Andric     OS << formatv("  {{\"{}\", {}, {}},\n", Name, Offset, Count);
234*700637cbSDimitry Andric   OS << R"(};
235*700637cbSDimitry Andric #endif
236*700637cbSDimitry Andric 
237*700637cbSDimitry Andric )";
238*700637cbSDimitry Andric }
239*700637cbSDimitry Andric 
EmitIntrinsicToNameTable(const CodeGenIntrinsicTable & Ints,raw_ostream & OS)240*700637cbSDimitry Andric void IntrinsicEmitter::EmitIntrinsicToNameTable(
241*700637cbSDimitry Andric     const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {
242*700637cbSDimitry Andric   // Built up a table of the intrinsic names.
243*700637cbSDimitry Andric   constexpr StringLiteral NotIntrinsic = "not_intrinsic";
244*700637cbSDimitry Andric   StringToOffsetTable Table;
245*700637cbSDimitry Andric   Table.GetOrAddStringOffset(NotIntrinsic);
246*700637cbSDimitry Andric   for (const auto &Int : Ints)
247*700637cbSDimitry Andric     Table.GetOrAddStringOffset(Int.Name);
248*700637cbSDimitry Andric 
249*700637cbSDimitry Andric   OS << R"(// Intrinsic ID to name table.
250*700637cbSDimitry Andric #ifdef GET_INTRINSIC_NAME_TABLE
251*700637cbSDimitry Andric // Note that entry #0 is the invalid intrinsic!
252*700637cbSDimitry Andric 
253*700637cbSDimitry Andric )";
254*700637cbSDimitry Andric 
255*700637cbSDimitry Andric   Table.EmitStringTableDef(OS, "IntrinsicNameTable");
256*700637cbSDimitry Andric 
257*700637cbSDimitry Andric   OS << R"(
258*700637cbSDimitry Andric static constexpr unsigned IntrinsicNameOffsetTable[] = {
259*700637cbSDimitry Andric )";
260*700637cbSDimitry Andric 
261*700637cbSDimitry Andric   OS << formatv("  {}, // {}\n", Table.GetStringOffset(NotIntrinsic),
262*700637cbSDimitry Andric                 NotIntrinsic);
263*700637cbSDimitry Andric   for (const auto &Int : Ints)
264*700637cbSDimitry Andric     OS << formatv("  {}, // {}\n", Table.GetStringOffset(Int.Name), Int.Name);
265*700637cbSDimitry Andric 
266*700637cbSDimitry Andric   OS << R"(
267*700637cbSDimitry Andric }; // IntrinsicNameOffsetTable
268*700637cbSDimitry Andric 
269*700637cbSDimitry Andric #endif
270*700637cbSDimitry Andric 
271*700637cbSDimitry Andric )";
272*700637cbSDimitry Andric }
273*700637cbSDimitry Andric 
EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable & Ints,raw_ostream & OS)274*700637cbSDimitry Andric void IntrinsicEmitter::EmitIntrinsicToOverloadTable(
275*700637cbSDimitry Andric     const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {
276*700637cbSDimitry Andric   OS << R"(// Intrinsic ID to overload bitset.
277*700637cbSDimitry Andric #ifdef GET_INTRINSIC_OVERLOAD_TABLE
278*700637cbSDimitry Andric static constexpr uint8_t OTable[] = {
279*700637cbSDimitry Andric   0
280*700637cbSDimitry Andric   )";
281*700637cbSDimitry Andric   for (auto [I, Int] : enumerate(Ints)) {
282*700637cbSDimitry Andric     // Add one to the index so we emit a null bit for the invalid #0 intrinsic.
283*700637cbSDimitry Andric     size_t Idx = I + 1;
284*700637cbSDimitry Andric 
285*700637cbSDimitry Andric     if (Idx % 8 == 0)
286*700637cbSDimitry Andric       OS << ",\n  0";
287*700637cbSDimitry Andric     if (Int.isOverloaded)
288*700637cbSDimitry Andric       OS << " | (1<<" << Idx % 8 << ')';
289*700637cbSDimitry Andric   }
290*700637cbSDimitry Andric   OS << "\n};\n\n";
291*700637cbSDimitry Andric   // OTable contains a true bit at the position if the intrinsic is overloaded.
292*700637cbSDimitry Andric   OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n";
293*700637cbSDimitry Andric   OS << "#endif\n\n";
294*700637cbSDimitry Andric }
295*700637cbSDimitry Andric 
296*700637cbSDimitry Andric using TypeSigTy = SmallVector<unsigned char>;
297*700637cbSDimitry Andric 
298*700637cbSDimitry Andric /// Computes type signature of the intrinsic \p Int.
ComputeTypeSignature(const CodeGenIntrinsic & Int)299*700637cbSDimitry Andric static TypeSigTy ComputeTypeSignature(const CodeGenIntrinsic &Int) {
300*700637cbSDimitry Andric   TypeSigTy TypeSig;
301*700637cbSDimitry Andric   const Record *TypeInfo = Int.TheDef->getValueAsDef("TypeInfo");
302*700637cbSDimitry Andric   const ListInit *TypeList = TypeInfo->getValueAsListInit("TypeSig");
303*700637cbSDimitry Andric 
304*700637cbSDimitry Andric   for (const auto *TypeListEntry : TypeList->getElements())
305*700637cbSDimitry Andric     TypeSig.emplace_back(cast<IntInit>(TypeListEntry)->getValue());
306*700637cbSDimitry Andric   return TypeSig;
307*700637cbSDimitry Andric }
308*700637cbSDimitry Andric 
309*700637cbSDimitry Andric // Pack the type signature into 32-bit fixed encoding word.
encodePacked(const TypeSigTy & TypeSig)310*700637cbSDimitry Andric static std::optional<uint32_t> encodePacked(const TypeSigTy &TypeSig) {
311*700637cbSDimitry Andric   if (TypeSig.size() > 8)
312*700637cbSDimitry Andric     return std::nullopt;
313*700637cbSDimitry Andric 
314*700637cbSDimitry Andric   uint32_t Result = 0;
315*700637cbSDimitry Andric   for (unsigned char C : reverse(TypeSig)) {
316*700637cbSDimitry Andric     if (C > 15)
317*700637cbSDimitry Andric       return std::nullopt;
318*700637cbSDimitry Andric     Result = (Result << 4) | C;
319*700637cbSDimitry Andric   }
320*700637cbSDimitry Andric   return Result;
321*700637cbSDimitry Andric }
322*700637cbSDimitry Andric 
EmitGenerator(const CodeGenIntrinsicTable & Ints,raw_ostream & OS)323*700637cbSDimitry Andric void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
324*700637cbSDimitry Andric                                      raw_ostream &OS) {
325*700637cbSDimitry Andric   // Note: the code below can be switched to use 32-bit fixed encoding by
326*700637cbSDimitry Andric   // flipping the flag below.
327*700637cbSDimitry Andric   constexpr bool Use16BitFixedEncoding = true;
328*700637cbSDimitry Andric   using FixedEncodingTy =
329*700637cbSDimitry Andric       std::conditional_t<Use16BitFixedEncoding, uint16_t, uint32_t>;
330*700637cbSDimitry Andric   constexpr unsigned FixedEncodingBits = sizeof(FixedEncodingTy) * CHAR_BIT;
331*700637cbSDimitry Andric   // Mask with all bits 1 except the most significant bit.
332*700637cbSDimitry Andric   const unsigned Mask = (1U << (FixedEncodingBits - 1)) - 1;
333*700637cbSDimitry Andric   const unsigned MSBPostion = FixedEncodingBits - 1;
334*700637cbSDimitry Andric   StringRef FixedEncodingTypeName =
335*700637cbSDimitry Andric       Use16BitFixedEncoding ? "uint16_t" : "uint32_t";
336*700637cbSDimitry Andric 
337*700637cbSDimitry Andric   // If we can compute a 16/32-bit fixed encoding for this intrinsic, do so and
338*700637cbSDimitry Andric   // capture it in this vector, otherwise store a ~0U.
339*700637cbSDimitry Andric   std::vector<FixedEncodingTy> FixedEncodings;
340*700637cbSDimitry Andric   SequenceToOffsetTable<TypeSigTy> LongEncodingTable;
341*700637cbSDimitry Andric 
342*700637cbSDimitry Andric   FixedEncodings.reserve(Ints.size());
343*700637cbSDimitry Andric 
344*700637cbSDimitry Andric   // Compute the unique argument type info.
345*700637cbSDimitry Andric   for (const CodeGenIntrinsic &Int : Ints) {
346*700637cbSDimitry Andric     // Get the signature for the intrinsic.
347*700637cbSDimitry Andric     TypeSigTy TypeSig = ComputeTypeSignature(Int);
348*700637cbSDimitry Andric 
349*700637cbSDimitry Andric     // Check to see if we can encode it into a 16/32 bit word.
350*700637cbSDimitry Andric     std::optional<uint32_t> Result = encodePacked(TypeSig);
351*700637cbSDimitry Andric     if (Result && (*Result & Mask) == Result) {
352*700637cbSDimitry Andric       FixedEncodings.push_back(static_cast<FixedEncodingTy>(*Result));
353*700637cbSDimitry Andric       continue;
354*700637cbSDimitry Andric     }
355*700637cbSDimitry Andric 
356*700637cbSDimitry Andric     LongEncodingTable.add(TypeSig);
357*700637cbSDimitry Andric 
358*700637cbSDimitry Andric     // This is a placehold that we'll replace after the table is laid out.
359*700637cbSDimitry Andric     FixedEncodings.push_back(static_cast<FixedEncodingTy>(~0U));
360*700637cbSDimitry Andric   }
361*700637cbSDimitry Andric 
362*700637cbSDimitry Andric   LongEncodingTable.layout();
363*700637cbSDimitry Andric 
364*700637cbSDimitry Andric   OS << formatv(R"(// Global intrinsic function declaration type table.
365*700637cbSDimitry Andric #ifdef GET_INTRINSIC_GENERATOR_GLOBAL
366*700637cbSDimitry Andric static constexpr {} IIT_Table[] = {{
367*700637cbSDimitry Andric   )",
368*700637cbSDimitry Andric                 FixedEncodingTypeName);
369*700637cbSDimitry Andric 
370*700637cbSDimitry Andric   unsigned MaxOffset = 0;
371*700637cbSDimitry Andric   for (auto [Idx, FixedEncoding, Int] : enumerate(FixedEncodings, Ints)) {
372*700637cbSDimitry Andric     if ((Idx & 7) == 7)
373*700637cbSDimitry Andric       OS << "\n  ";
374*700637cbSDimitry Andric 
375*700637cbSDimitry Andric     // If the entry fit in the table, just emit it.
376*700637cbSDimitry Andric     if ((FixedEncoding & Mask) == FixedEncoding) {
377*700637cbSDimitry Andric       OS << "0x" << Twine::utohexstr(FixedEncoding) << ", ";
378*700637cbSDimitry Andric       continue;
379*700637cbSDimitry Andric     }
380*700637cbSDimitry Andric 
381*700637cbSDimitry Andric     TypeSigTy TypeSig = ComputeTypeSignature(Int);
382*700637cbSDimitry Andric     unsigned Offset = LongEncodingTable.get(TypeSig);
383*700637cbSDimitry Andric     MaxOffset = std::max(MaxOffset, Offset);
384*700637cbSDimitry Andric 
385*700637cbSDimitry Andric     // Otherwise, emit the offset into the long encoding table.  We emit it this
386*700637cbSDimitry Andric     // way so that it is easier to read the offset in the .def file.
387*700637cbSDimitry Andric     OS << formatv("(1U<<{}) | {}, ", MSBPostion, Offset);
388*700637cbSDimitry Andric   }
389*700637cbSDimitry Andric 
390*700637cbSDimitry Andric   OS << "0\n};\n\n";
391*700637cbSDimitry Andric 
392*700637cbSDimitry Andric   // verify that all offsets will fit in 16/32 bits.
393*700637cbSDimitry Andric   if ((MaxOffset & Mask) != MaxOffset)
394*700637cbSDimitry Andric     PrintFatalError("Offset of long encoding table exceeds encoding bits");
395*700637cbSDimitry Andric 
396*700637cbSDimitry Andric   // Emit the shared table of register lists.
397*700637cbSDimitry Andric   OS << "static constexpr unsigned char IIT_LongEncodingTable[] = {\n";
398*700637cbSDimitry Andric   if (!LongEncodingTable.empty())
399*700637cbSDimitry Andric     LongEncodingTable.emit(
400*700637cbSDimitry Andric         OS, [](raw_ostream &OS, unsigned char C) { OS << (unsigned)C; });
401*700637cbSDimitry Andric   OS << "  255\n};\n";
402*700637cbSDimitry Andric   OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL
403*700637cbSDimitry Andric }
404*700637cbSDimitry Andric 
405*700637cbSDimitry Andric /// Returns the effective MemoryEffects for intrinsic \p Int.
getEffectiveME(const CodeGenIntrinsic & Int)406*700637cbSDimitry Andric static MemoryEffects getEffectiveME(const CodeGenIntrinsic &Int) {
407*700637cbSDimitry Andric   MemoryEffects ME = Int.ME;
408*700637cbSDimitry Andric   // TODO: IntrHasSideEffects should affect not only readnone intrinsics.
409*700637cbSDimitry Andric   if (ME.doesNotAccessMemory() && Int.hasSideEffects)
410*700637cbSDimitry Andric     ME = MemoryEffects::unknown();
411*700637cbSDimitry Andric   return ME;
412*700637cbSDimitry Andric }
413*700637cbSDimitry Andric 
compareFnAttributes(const CodeGenIntrinsic * L,const CodeGenIntrinsic * R)414*700637cbSDimitry Andric static bool compareFnAttributes(const CodeGenIntrinsic *L,
415*700637cbSDimitry Andric                                 const CodeGenIntrinsic *R) {
416*700637cbSDimitry Andric   auto TieBoolAttributes = [](const CodeGenIntrinsic *I) -> auto {
417*700637cbSDimitry Andric     // Sort throwing intrinsics after non-throwing intrinsics.
418*700637cbSDimitry Andric     return std::tie(I->canThrow, I->isNoDuplicate, I->isNoMerge, I->isNoReturn,
419*700637cbSDimitry Andric                     I->isNoCallback, I->isNoSync, I->isNoFree, I->isWillReturn,
420*700637cbSDimitry Andric                     I->isCold, I->isConvergent, I->isSpeculatable,
421*700637cbSDimitry Andric                     I->hasSideEffects, I->isStrictFP);
422*700637cbSDimitry Andric   };
423*700637cbSDimitry Andric 
424*700637cbSDimitry Andric   auto TieL = TieBoolAttributes(L);
425*700637cbSDimitry Andric   auto TieR = TieBoolAttributes(R);
426*700637cbSDimitry Andric 
427*700637cbSDimitry Andric   if (TieL != TieR)
428*700637cbSDimitry Andric     return TieL < TieR;
429*700637cbSDimitry Andric 
430*700637cbSDimitry Andric   // Try to order by readonly/readnone attribute.
431*700637cbSDimitry Andric   uint32_t LME = getEffectiveME(*L).toIntValue();
432*700637cbSDimitry Andric   uint32_t RME = getEffectiveME(*R).toIntValue();
433*700637cbSDimitry Andric   if (LME != RME)
434*700637cbSDimitry Andric     return LME > RME;
435*700637cbSDimitry Andric 
436*700637cbSDimitry Andric   return false;
437*700637cbSDimitry Andric }
438*700637cbSDimitry Andric 
439*700637cbSDimitry Andric /// Returns true if \p Int has a non-empty set of function attributes. Note that
440*700637cbSDimitry Andric /// NoUnwind = !canThrow, so we need to negate it's sense to test if the
441*700637cbSDimitry Andric // intrinsic has NoUnwind attribute.
hasFnAttributes(const CodeGenIntrinsic & Int)442*700637cbSDimitry Andric static bool hasFnAttributes(const CodeGenIntrinsic &Int) {
443*700637cbSDimitry Andric   return !Int.canThrow || Int.isNoReturn || Int.isNoCallback || Int.isNoSync ||
444*700637cbSDimitry Andric          Int.isNoFree || Int.isWillReturn || Int.isCold || Int.isNoDuplicate ||
445*700637cbSDimitry Andric          Int.isNoMerge || Int.isConvergent || Int.isSpeculatable ||
446*700637cbSDimitry Andric          Int.isStrictFP || getEffectiveME(Int) != MemoryEffects::unknown();
447*700637cbSDimitry Andric }
448*700637cbSDimitry Andric 
449*700637cbSDimitry Andric namespace {
450*700637cbSDimitry Andric struct FnAttributeComparator {
operator ()__anon0d85a4b90611::FnAttributeComparator451*700637cbSDimitry Andric   bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
452*700637cbSDimitry Andric     return compareFnAttributes(L, R);
453*700637cbSDimitry Andric   }
454*700637cbSDimitry Andric };
455*700637cbSDimitry Andric 
456*700637cbSDimitry Andric struct AttributeComparator {
operator ()__anon0d85a4b90611::AttributeComparator457*700637cbSDimitry Andric   bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
458*700637cbSDimitry Andric     // Order all intrinsics with no functiona attributes before all intrinsics
459*700637cbSDimitry Andric     // with function attributes.
460*700637cbSDimitry Andric     bool HasFnAttrLHS = hasFnAttributes(*L);
461*700637cbSDimitry Andric     bool HasFnAttrRHS = hasFnAttributes(*R);
462*700637cbSDimitry Andric 
463*700637cbSDimitry Andric     // Order by argument attributes if function `hasFnAttributes` is equal.
464*700637cbSDimitry Andric     // This is reliable because each side is already sorted internally.
465*700637cbSDimitry Andric     return std::tie(HasFnAttrLHS, L->ArgumentAttributes) <
466*700637cbSDimitry Andric            std::tie(HasFnAttrRHS, R->ArgumentAttributes);
467*700637cbSDimitry Andric   }
468*700637cbSDimitry Andric };
469*700637cbSDimitry Andric } // End anonymous namespace
470*700637cbSDimitry Andric 
471*700637cbSDimitry Andric /// Returns the name of the IR enum for argument attribute kind \p Kind.
getArgAttrEnumName(CodeGenIntrinsic::ArgAttrKind Kind)472*700637cbSDimitry Andric static StringRef getArgAttrEnumName(CodeGenIntrinsic::ArgAttrKind Kind) {
473*700637cbSDimitry Andric   switch (Kind) {
474*700637cbSDimitry Andric   case CodeGenIntrinsic::NoCapture:
475*700637cbSDimitry Andric     llvm_unreachable("Handled separately");
476*700637cbSDimitry Andric   case CodeGenIntrinsic::NoAlias:
477*700637cbSDimitry Andric     return "NoAlias";
478*700637cbSDimitry Andric   case CodeGenIntrinsic::NoUndef:
479*700637cbSDimitry Andric     return "NoUndef";
480*700637cbSDimitry Andric   case CodeGenIntrinsic::NonNull:
481*700637cbSDimitry Andric     return "NonNull";
482*700637cbSDimitry Andric   case CodeGenIntrinsic::Returned:
483*700637cbSDimitry Andric     return "Returned";
484*700637cbSDimitry Andric   case CodeGenIntrinsic::ReadOnly:
485*700637cbSDimitry Andric     return "ReadOnly";
486*700637cbSDimitry Andric   case CodeGenIntrinsic::WriteOnly:
487*700637cbSDimitry Andric     return "WriteOnly";
488*700637cbSDimitry Andric   case CodeGenIntrinsic::ReadNone:
489*700637cbSDimitry Andric     return "ReadNone";
490*700637cbSDimitry Andric   case CodeGenIntrinsic::ImmArg:
491*700637cbSDimitry Andric     return "ImmArg";
492*700637cbSDimitry Andric   case CodeGenIntrinsic::Alignment:
493*700637cbSDimitry Andric     return "Alignment";
494*700637cbSDimitry Andric   case CodeGenIntrinsic::Dereferenceable:
495*700637cbSDimitry Andric     return "Dereferenceable";
496*700637cbSDimitry Andric   case CodeGenIntrinsic::Range:
497*700637cbSDimitry Andric     return "Range";
498*700637cbSDimitry Andric   }
499*700637cbSDimitry Andric   llvm_unreachable("Unknown CodeGenIntrinsic::ArgAttrKind enum");
500*700637cbSDimitry Andric }
501*700637cbSDimitry Andric 
502*700637cbSDimitry Andric /// EmitAttributes - This emits the Intrinsic::getAttributes method.
EmitAttributes(const CodeGenIntrinsicTable & Ints,raw_ostream & OS)503*700637cbSDimitry Andric void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
504*700637cbSDimitry Andric                                       raw_ostream &OS) {
505*700637cbSDimitry Andric   OS << R"(// Add parameter attributes that are not common to all intrinsics.
506*700637cbSDimitry Andric #ifdef GET_INTRINSIC_ATTRIBUTES
507*700637cbSDimitry Andric static AttributeSet getIntrinsicArgAttributeSet(LLVMContext &C, unsigned ID,
508*700637cbSDimitry Andric                                                 Type *ArgType) {
509*700637cbSDimitry Andric   unsigned BitWidth = ArgType->getScalarSizeInBits();
510*700637cbSDimitry Andric   switch (ID) {
511*700637cbSDimitry Andric   default: llvm_unreachable("Invalid attribute set number");)";
512*700637cbSDimitry Andric   // Compute unique argument attribute sets.
513*700637cbSDimitry Andric   std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned>
514*700637cbSDimitry Andric       UniqArgAttributes;
515*700637cbSDimitry Andric   for (const CodeGenIntrinsic &Int : Ints) {
516*700637cbSDimitry Andric     for (auto &Attrs : Int.ArgumentAttributes) {
517*700637cbSDimitry Andric       if (Attrs.empty())
518*700637cbSDimitry Andric         continue;
519*700637cbSDimitry Andric 
520*700637cbSDimitry Andric       unsigned ID = UniqArgAttributes.size();
521*700637cbSDimitry Andric       if (!UniqArgAttributes.try_emplace(Attrs, ID).second)
522*700637cbSDimitry Andric         continue;
523*700637cbSDimitry Andric 
524*700637cbSDimitry Andric       assert(is_sorted(Attrs) && "Argument attributes are not sorted");
525*700637cbSDimitry Andric 
526*700637cbSDimitry Andric       OS << formatv(R"(
527*700637cbSDimitry Andric   case {}:
528*700637cbSDimitry Andric     return AttributeSet::get(C, {{
529*700637cbSDimitry Andric )",
530*700637cbSDimitry Andric                     ID);
531*700637cbSDimitry Andric       for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) {
532*700637cbSDimitry Andric         if (Attr.Kind == CodeGenIntrinsic::NoCapture) {
533*700637cbSDimitry Andric           OS << "      Attribute::getWithCaptureInfo(C, "
534*700637cbSDimitry Andric                 "CaptureInfo::none()),\n";
535*700637cbSDimitry Andric           continue;
536*700637cbSDimitry Andric         }
537*700637cbSDimitry Andric         StringRef AttrName = getArgAttrEnumName(Attr.Kind);
538*700637cbSDimitry Andric         if (Attr.Kind == CodeGenIntrinsic::Alignment ||
539*700637cbSDimitry Andric             Attr.Kind == CodeGenIntrinsic::Dereferenceable)
540*700637cbSDimitry Andric           OS << formatv("      Attribute::get(C, Attribute::{}, {}),\n",
541*700637cbSDimitry Andric                         AttrName, Attr.Value);
542*700637cbSDimitry Andric         else if (Attr.Kind == CodeGenIntrinsic::Range)
543*700637cbSDimitry Andric           // This allows implicitTrunc because the range may only fit the
544*700637cbSDimitry Andric           // type based on rules implemented in the IR verifier. E.g. the
545*700637cbSDimitry Andric           // [-1, 1] range for ucmp/scmp intrinsics requires a minimum i2 type.
546*700637cbSDimitry Andric           // Give the verifier a chance to diagnose this instead of asserting
547*700637cbSDimitry Andric           // here.
548*700637cbSDimitry Andric           OS << formatv("      Attribute::get(C, Attribute::{}, "
549*700637cbSDimitry Andric                         "ConstantRange(APInt(BitWidth, {}, /*isSigned=*/true, "
550*700637cbSDimitry Andric                         "/*implicitTrunc=*/true), APInt(BitWidth, {}, "
551*700637cbSDimitry Andric                         "/*isSigned=*/true, /*implicitTrunc=*/true))),\n",
552*700637cbSDimitry Andric                         AttrName, (int64_t)Attr.Value, (int64_t)Attr.Value2);
553*700637cbSDimitry Andric         else
554*700637cbSDimitry Andric           OS << formatv("      Attribute::get(C, Attribute::{}),\n", AttrName);
555*700637cbSDimitry Andric       }
556*700637cbSDimitry Andric       OS << "    });";
557*700637cbSDimitry Andric     }
558*700637cbSDimitry Andric   }
559*700637cbSDimitry Andric   OS << R"(
560*700637cbSDimitry Andric   }
561*700637cbSDimitry Andric } // getIntrinsicArgAttributeSet
562*700637cbSDimitry Andric )";
563*700637cbSDimitry Andric 
564*700637cbSDimitry Andric   // Compute unique function attribute sets.
565*700637cbSDimitry Andric   std::map<const CodeGenIntrinsic *, unsigned, FnAttributeComparator>
566*700637cbSDimitry Andric       UniqFnAttributes;
567*700637cbSDimitry Andric   OS << R"(
568*700637cbSDimitry Andric static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) {
569*700637cbSDimitry Andric   switch (ID) {
570*700637cbSDimitry Andric     default: llvm_unreachable("Invalid attribute set number");)";
571*700637cbSDimitry Andric 
572*700637cbSDimitry Andric   for (const CodeGenIntrinsic &Int : Ints) {
573*700637cbSDimitry Andric     unsigned ID = UniqFnAttributes.size();
574*700637cbSDimitry Andric     if (!UniqFnAttributes.try_emplace(&Int, ID).second)
575*700637cbSDimitry Andric       continue;
576*700637cbSDimitry Andric     OS << formatv(R"(
577*700637cbSDimitry Andric   case {}:
578*700637cbSDimitry Andric     return AttributeSet::get(C, {{
579*700637cbSDimitry Andric )",
580*700637cbSDimitry Andric                   ID);
581*700637cbSDimitry Andric     auto addAttribute = [&OS](StringRef Attr) {
582*700637cbSDimitry Andric       OS << formatv("      Attribute::get(C, Attribute::{}),\n", Attr);
583*700637cbSDimitry Andric     };
584*700637cbSDimitry Andric     if (!Int.canThrow)
585*700637cbSDimitry Andric       addAttribute("NoUnwind");
586*700637cbSDimitry Andric     if (Int.isNoReturn)
587*700637cbSDimitry Andric       addAttribute("NoReturn");
588*700637cbSDimitry Andric     if (Int.isNoCallback)
589*700637cbSDimitry Andric       addAttribute("NoCallback");
590*700637cbSDimitry Andric     if (Int.isNoSync)
591*700637cbSDimitry Andric       addAttribute("NoSync");
592*700637cbSDimitry Andric     if (Int.isNoFree)
593*700637cbSDimitry Andric       addAttribute("NoFree");
594*700637cbSDimitry Andric     if (Int.isWillReturn)
595*700637cbSDimitry Andric       addAttribute("WillReturn");
596*700637cbSDimitry Andric     if (Int.isCold)
597*700637cbSDimitry Andric       addAttribute("Cold");
598*700637cbSDimitry Andric     if (Int.isNoDuplicate)
599*700637cbSDimitry Andric       addAttribute("NoDuplicate");
600*700637cbSDimitry Andric     if (Int.isNoMerge)
601*700637cbSDimitry Andric       addAttribute("NoMerge");
602*700637cbSDimitry Andric     if (Int.isConvergent)
603*700637cbSDimitry Andric       addAttribute("Convergent");
604*700637cbSDimitry Andric     if (Int.isSpeculatable)
605*700637cbSDimitry Andric       addAttribute("Speculatable");
606*700637cbSDimitry Andric     if (Int.isStrictFP)
607*700637cbSDimitry Andric       addAttribute("StrictFP");
608*700637cbSDimitry Andric 
609*700637cbSDimitry Andric     const MemoryEffects ME = getEffectiveME(Int);
610*700637cbSDimitry Andric     if (ME != MemoryEffects::unknown()) {
611*700637cbSDimitry Andric       OS << formatv("      // {}\n", ME);
612*700637cbSDimitry Andric       OS << formatv("      Attribute::getWithMemoryEffects(C, "
613*700637cbSDimitry Andric                     "MemoryEffects::createFromIntValue({})),\n",
614*700637cbSDimitry Andric                     ME.toIntValue());
615*700637cbSDimitry Andric     }
616*700637cbSDimitry Andric     OS << "    });";
617*700637cbSDimitry Andric   }
618*700637cbSDimitry Andric   OS << R"(
619*700637cbSDimitry Andric   }
620*700637cbSDimitry Andric } // getIntrinsicFnAttributeSet
621*700637cbSDimitry Andric 
622*700637cbSDimitry Andric static constexpr uint16_t IntrinsicsToAttributesMap[] = {)";
623*700637cbSDimitry Andric 
624*700637cbSDimitry Andric   // Compute the maximum number of attribute arguments and the map. For function
625*700637cbSDimitry Andric   // attributes, we only consider whether the intrinsics has any function
626*700637cbSDimitry Andric   // arguments or not.
627*700637cbSDimitry Andric   std::map<const CodeGenIntrinsic *, unsigned, AttributeComparator>
628*700637cbSDimitry Andric       UniqAttributes;
629*700637cbSDimitry Andric   for (const CodeGenIntrinsic &Int : Ints) {
630*700637cbSDimitry Andric     unsigned ID = UniqAttributes.size();
631*700637cbSDimitry Andric     UniqAttributes.try_emplace(&Int, ID);
632*700637cbSDimitry Andric   }
633*700637cbSDimitry Andric 
634*700637cbSDimitry Andric   // Emit an array of AttributeList.  Most intrinsics will have at least one
635*700637cbSDimitry Andric   // entry, for the function itself (index ~1), which is usually nounwind.
636*700637cbSDimitry Andric   for (const CodeGenIntrinsic &Int : Ints) {
637*700637cbSDimitry Andric     uint16_t FnAttrIndex = UniqFnAttributes[&Int];
638*700637cbSDimitry Andric     OS << formatv("\n    {} << 8 | {}, // {}", FnAttrIndex,
639*700637cbSDimitry Andric                   UniqAttributes[&Int], Int.Name);
640*700637cbSDimitry Andric   }
641*700637cbSDimitry Andric 
642*700637cbSDimitry Andric   // Assign a 16-bit packed ID for each intrinsic. The lower 8-bits will be its
643*700637cbSDimitry Andric   // "argument attribute ID" (index in UniqAttributes) and upper 8 bits will be
644*700637cbSDimitry Andric   // its "function attribute ID" (index in UniqFnAttributes).
645*700637cbSDimitry Andric   if (UniqAttributes.size() > 256)
646*700637cbSDimitry Andric     PrintFatalError("Too many unique argument attributes for table!");
647*700637cbSDimitry Andric   if (UniqFnAttributes.size() > 256)
648*700637cbSDimitry Andric     PrintFatalError("Too many unique function attributes for table!");
649*700637cbSDimitry Andric 
650*700637cbSDimitry Andric   OS << R"(
651*700637cbSDimitry Andric };
652*700637cbSDimitry Andric 
653*700637cbSDimitry Andric AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id,
654*700637cbSDimitry Andric                                        FunctionType *FT) {)";
655*700637cbSDimitry Andric 
656*700637cbSDimitry Andric   OS << formatv(R"(
657*700637cbSDimitry Andric   if (id == 0)
658*700637cbSDimitry Andric     return AttributeList();
659*700637cbSDimitry Andric 
660*700637cbSDimitry Andric   uint16_t PackedID = IntrinsicsToAttributesMap[id - 1];
661*700637cbSDimitry Andric   uint8_t FnAttrID = PackedID >> 8;
662*700637cbSDimitry Andric   switch(PackedID & 0xFF) {{
663*700637cbSDimitry Andric     default: llvm_unreachable("Invalid attribute number");
664*700637cbSDimitry Andric )");
665*700637cbSDimitry Andric 
666*700637cbSDimitry Andric   for (const auto [IntPtr, UniqueID] : UniqAttributes) {
667*700637cbSDimitry Andric     OS << formatv("  case {}:\n", UniqueID);
668*700637cbSDimitry Andric     const CodeGenIntrinsic &Int = *IntPtr;
669*700637cbSDimitry Andric 
670*700637cbSDimitry Andric     // Keep track of the number of attributes we're writing out.
671*700637cbSDimitry Andric     unsigned NumAttrs =
672*700637cbSDimitry Andric         llvm::count_if(Int.ArgumentAttributes,
673*700637cbSDimitry Andric                        [](const auto &Attrs) { return !Attrs.empty(); });
674*700637cbSDimitry Andric     NumAttrs += hasFnAttributes(Int);
675*700637cbSDimitry Andric     if (NumAttrs == 0) {
676*700637cbSDimitry Andric       OS << "    return AttributeList();\n";
677*700637cbSDimitry Andric       continue;
678*700637cbSDimitry Andric     }
679*700637cbSDimitry Andric 
680*700637cbSDimitry Andric     OS << "    return AttributeList::get(C, {\n";
681*700637cbSDimitry Andric     ListSeparator LS(",\n");
682*700637cbSDimitry Andric     for (const auto &[AttrIdx, Attrs] : enumerate(Int.ArgumentAttributes)) {
683*700637cbSDimitry Andric       if (Attrs.empty())
684*700637cbSDimitry Andric         continue;
685*700637cbSDimitry Andric 
686*700637cbSDimitry Andric       unsigned ArgAttrID = UniqArgAttributes.find(Attrs)->second;
687*700637cbSDimitry Andric       OS << LS
688*700637cbSDimitry Andric          << formatv("      {{{}, getIntrinsicArgAttributeSet(C, {}, "
689*700637cbSDimitry Andric                     "FT->getContainedType({}))}",
690*700637cbSDimitry Andric                     AttrIdx, ArgAttrID, AttrIdx);
691*700637cbSDimitry Andric     }
692*700637cbSDimitry Andric 
693*700637cbSDimitry Andric     if (hasFnAttributes(Int)) {
694*700637cbSDimitry Andric       OS << LS
695*700637cbSDimitry Andric          << "      {AttributeList::FunctionIndex, "
696*700637cbSDimitry Andric             "getIntrinsicFnAttributeSet(C, FnAttrID)}";
697*700637cbSDimitry Andric     }
698*700637cbSDimitry Andric     OS << "\n    });\n";
699*700637cbSDimitry Andric   }
700*700637cbSDimitry Andric 
701*700637cbSDimitry Andric   OS << R"(  }
702*700637cbSDimitry Andric }
703*700637cbSDimitry Andric #endif // GET_INTRINSIC_ATTRIBUTES
704*700637cbSDimitry Andric 
705*700637cbSDimitry Andric )";
706*700637cbSDimitry Andric }
707*700637cbSDimitry Andric 
EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable & Ints,bool IsClang,raw_ostream & OS)708*700637cbSDimitry Andric void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(
709*700637cbSDimitry Andric     const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) {
710*700637cbSDimitry Andric   StringRef CompilerName = IsClang ? "Clang" : "MS";
711*700637cbSDimitry Andric   StringRef UpperCompilerName = IsClang ? "CLANG" : "MS";
712*700637cbSDimitry Andric 
713*700637cbSDimitry Andric   // map<TargetPrefix, pair<map<BuiltinName, EnumName>, CommonPrefix>.
714*700637cbSDimitry Andric   // Note that we iterate over both the maps in the code below and both
715*700637cbSDimitry Andric   // iterations need to iterate in sorted key order. For the inner map, entries
716*700637cbSDimitry Andric   // need to be emitted in the sorted order of `BuiltinName` with `CommonPrefix`
717*700637cbSDimitry Andric   // rempved, because we use std::lower_bound to search these entries. For the
718*700637cbSDimitry Andric   // outer map as well, entries need to be emitted in sorter order of
719*700637cbSDimitry Andric   // `TargetPrefix` as we use std::lower_bound to search these entries.
720*700637cbSDimitry Andric   using BIMEntryTy =
721*700637cbSDimitry Andric       std::pair<std::map<StringRef, StringRef>, std::optional<StringRef>>;
722*700637cbSDimitry Andric   std::map<StringRef, BIMEntryTy> BuiltinMap;
723*700637cbSDimitry Andric 
724*700637cbSDimitry Andric   for (const CodeGenIntrinsic &Int : Ints) {
725*700637cbSDimitry Andric     StringRef BuiltinName = IsClang ? Int.ClangBuiltinName : Int.MSBuiltinName;
726*700637cbSDimitry Andric     if (BuiltinName.empty())
727*700637cbSDimitry Andric       continue;
728*700637cbSDimitry Andric     // Get the map for this target prefix.
729*700637cbSDimitry Andric     auto &[Map, CommonPrefix] = BuiltinMap[Int.TargetPrefix];
730*700637cbSDimitry Andric 
731*700637cbSDimitry Andric     if (!Map.try_emplace(BuiltinName, Int.EnumName).second)
732*700637cbSDimitry Andric       PrintFatalError(Int.TheDef->getLoc(),
733*700637cbSDimitry Andric                       "Intrinsic '" + Int.TheDef->getName() + "': duplicate " +
734*700637cbSDimitry Andric                           CompilerName + " builtin name!");
735*700637cbSDimitry Andric 
736*700637cbSDimitry Andric     // Update common prefix.
737*700637cbSDimitry Andric     if (!CommonPrefix) {
738*700637cbSDimitry Andric       // For the first builtin for this target, initialize the common prefix.
739*700637cbSDimitry Andric       CommonPrefix = BuiltinName;
740*700637cbSDimitry Andric       continue;
741*700637cbSDimitry Andric     }
742*700637cbSDimitry Andric 
743*700637cbSDimitry Andric     // Update the common prefix. Note that this assumes that `take_front` will
744*700637cbSDimitry Andric     // never set the `Data` pointer in CommonPrefix to nullptr.
745*700637cbSDimitry Andric     const char *Mismatch = mismatch(*CommonPrefix, BuiltinName).first;
746*700637cbSDimitry Andric     *CommonPrefix = CommonPrefix->take_front(Mismatch - CommonPrefix->begin());
747*700637cbSDimitry Andric   }
748*700637cbSDimitry Andric 
749*700637cbSDimitry Andric   // Populate the string table with the names of all the builtins after
750*700637cbSDimitry Andric   // removing this common prefix.
751*700637cbSDimitry Andric   StringToOffsetTable Table;
752*700637cbSDimitry Andric   for (const auto &[TargetPrefix, Entry] : BuiltinMap) {
753*700637cbSDimitry Andric     auto &[Map, CommonPrefix] = Entry;
754*700637cbSDimitry Andric     for (auto &[BuiltinName, EnumName] : Map) {
755*700637cbSDimitry Andric       StringRef Suffix = BuiltinName.substr(CommonPrefix->size());
756*700637cbSDimitry Andric       Table.GetOrAddStringOffset(Suffix);
757*700637cbSDimitry Andric     }
758*700637cbSDimitry Andric   }
759*700637cbSDimitry Andric 
760*700637cbSDimitry Andric   OS << formatv(R"(
761*700637cbSDimitry Andric // Get the LLVM intrinsic that corresponds to a builtin. This is used by the
762*700637cbSDimitry Andric // C front-end. The builtin name is passed in as BuiltinName, and a target
763*700637cbSDimitry Andric // prefix (e.g. 'ppc') is passed in as TargetPrefix.
764*700637cbSDimitry Andric #ifdef GET_LLVM_INTRINSIC_FOR_{}_BUILTIN
765*700637cbSDimitry Andric Intrinsic::ID
766*700637cbSDimitry Andric Intrinsic::getIntrinsicFor{}Builtin(StringRef TargetPrefix,
767*700637cbSDimitry Andric                                       StringRef BuiltinName) {{
768*700637cbSDimitry Andric   using namespace Intrinsic;
769*700637cbSDimitry Andric )",
770*700637cbSDimitry Andric                 UpperCompilerName, CompilerName);
771*700637cbSDimitry Andric 
772*700637cbSDimitry Andric   if (BuiltinMap.empty()) {
773*700637cbSDimitry Andric     OS << formatv(R"(
774*700637cbSDimitry Andric   return not_intrinsic;
775*700637cbSDimitry Andric   }
776*700637cbSDimitry Andric #endif  // GET_LLVM_INTRINSIC_FOR_{}_BUILTIN
777*700637cbSDimitry Andric )",
778*700637cbSDimitry Andric                   UpperCompilerName);
779*700637cbSDimitry Andric     return;
780*700637cbSDimitry Andric   }
781*700637cbSDimitry Andric 
782*700637cbSDimitry Andric   if (!Table.empty()) {
783*700637cbSDimitry Andric     Table.EmitStringTableDef(OS, "BuiltinNames");
784*700637cbSDimitry Andric 
785*700637cbSDimitry Andric     OS << R"(
786*700637cbSDimitry Andric   struct BuiltinEntry {
787*700637cbSDimitry Andric     ID IntrinsicID;
788*700637cbSDimitry Andric     unsigned StrTabOffset;
789*700637cbSDimitry Andric     const char *getName() const { return BuiltinNames[StrTabOffset].data(); }
790*700637cbSDimitry Andric     bool operator<(StringRef RHS) const {
791*700637cbSDimitry Andric       return strncmp(getName(), RHS.data(), RHS.size()) < 0;
792*700637cbSDimitry Andric     }
793*700637cbSDimitry Andric   };
794*700637cbSDimitry Andric 
795*700637cbSDimitry Andric )";
796*700637cbSDimitry Andric   }
797*700637cbSDimitry Andric 
798*700637cbSDimitry Andric   // Emit a per target table of bultin names.
799*700637cbSDimitry Andric   bool HasTargetIndependentBuiltins = false;
800*700637cbSDimitry Andric   StringRef TargetIndepndentCommonPrefix;
801*700637cbSDimitry Andric   for (const auto &[TargetPrefix, Entry] : BuiltinMap) {
802*700637cbSDimitry Andric     const auto &[Map, CommonPrefix] = Entry;
803*700637cbSDimitry Andric     if (!TargetPrefix.empty()) {
804*700637cbSDimitry Andric       OS << formatv("  // Builtins for {0}.\n", TargetPrefix);
805*700637cbSDimitry Andric     } else {
806*700637cbSDimitry Andric       OS << "  // Target independent builtins.\n";
807*700637cbSDimitry Andric       HasTargetIndependentBuiltins = true;
808*700637cbSDimitry Andric       TargetIndepndentCommonPrefix = *CommonPrefix;
809*700637cbSDimitry Andric     }
810*700637cbSDimitry Andric 
811*700637cbSDimitry Andric     // Emit the builtin table for this target prefix.
812*700637cbSDimitry Andric     OS << formatv("  static constexpr BuiltinEntry {}Names[] = {{\n",
813*700637cbSDimitry Andric                   TargetPrefix);
814*700637cbSDimitry Andric     for (const auto &[BuiltinName, EnumName] : Map) {
815*700637cbSDimitry Andric       StringRef Suffix = BuiltinName.substr(CommonPrefix->size());
816*700637cbSDimitry Andric       OS << formatv("    {{{}, {}}, // {}\n", EnumName,
817*700637cbSDimitry Andric                     *Table.GetStringOffset(Suffix), BuiltinName);
818*700637cbSDimitry Andric     }
819*700637cbSDimitry Andric     OS << formatv("  }; // {}Names\n\n", TargetPrefix);
820*700637cbSDimitry Andric   }
821*700637cbSDimitry Andric 
822*700637cbSDimitry Andric   // After emitting the builtin tables for all targets, emit a lookup table for
823*700637cbSDimitry Andric   // all targets. We will use binary search, similar to the table for builtin
824*700637cbSDimitry Andric   // names to lookup into this table.
825*700637cbSDimitry Andric   OS << R"(
826*700637cbSDimitry Andric   struct TargetEntry {
827*700637cbSDimitry Andric     StringLiteral TargetPrefix;
828*700637cbSDimitry Andric     ArrayRef<BuiltinEntry> Names;
829*700637cbSDimitry Andric     StringLiteral CommonPrefix;
830*700637cbSDimitry Andric     bool operator<(StringRef RHS) const {
831*700637cbSDimitry Andric       return TargetPrefix < RHS;
832*700637cbSDimitry Andric     };
833*700637cbSDimitry Andric   };
834*700637cbSDimitry Andric   static constexpr TargetEntry TargetTable[] = {
835*700637cbSDimitry Andric )";
836*700637cbSDimitry Andric 
837*700637cbSDimitry Andric   for (const auto &[TargetPrefix, Entry] : BuiltinMap) {
838*700637cbSDimitry Andric     const auto &[Map, CommonPrefix] = Entry;
839*700637cbSDimitry Andric     if (TargetPrefix.empty())
840*700637cbSDimitry Andric       continue;
841*700637cbSDimitry Andric     OS << formatv(R"(    {{"{0}", {0}Names, "{1}"},)", TargetPrefix,
842*700637cbSDimitry Andric                   CommonPrefix)
843*700637cbSDimitry Andric        << "\n";
844*700637cbSDimitry Andric   }
845*700637cbSDimitry Andric   OS << "  };\n";
846*700637cbSDimitry Andric 
847*700637cbSDimitry Andric   // Now for the actual lookup, first check the target independent table if
848*700637cbSDimitry Andric   // we emitted one.
849*700637cbSDimitry Andric   if (HasTargetIndependentBuiltins) {
850*700637cbSDimitry Andric     OS << formatv(R"(
851*700637cbSDimitry Andric   // Check if it's a target independent builtin.
852*700637cbSDimitry Andric   // Copy the builtin name so we can use it in consume_front without clobbering
853*700637cbSDimitry Andric   // if for the lookup in the target specific table.
854*700637cbSDimitry Andric   StringRef Suffix = BuiltinName;
855*700637cbSDimitry Andric   if (Suffix.consume_front("{}")) {{
856*700637cbSDimitry Andric     auto II = lower_bound(Names, Suffix);
857*700637cbSDimitry Andric     if (II != std::end(Names) && II->getName() == Suffix)
858*700637cbSDimitry Andric       return II->IntrinsicID;
859*700637cbSDimitry Andric   }
860*700637cbSDimitry Andric )",
861*700637cbSDimitry Andric                   TargetIndepndentCommonPrefix);
862*700637cbSDimitry Andric   }
863*700637cbSDimitry Andric 
864*700637cbSDimitry Andric   // If a target independent builtin was not found, lookup the target specific.
865*700637cbSDimitry Andric   OS << formatv(R"(
866*700637cbSDimitry Andric   auto TI = lower_bound(TargetTable, TargetPrefix);
867*700637cbSDimitry Andric   if (TI == std::end(TargetTable) || TI->TargetPrefix != TargetPrefix)
868*700637cbSDimitry Andric     return not_intrinsic;
869*700637cbSDimitry Andric   // This is the last use of BuiltinName, so no need to copy before using it in
870*700637cbSDimitry Andric   // consume_front.
871*700637cbSDimitry Andric   if (!BuiltinName.consume_front(TI->CommonPrefix))
872*700637cbSDimitry Andric     return not_intrinsic;
873*700637cbSDimitry Andric   auto II = lower_bound(TI->Names, BuiltinName);
874*700637cbSDimitry Andric   if (II == std::end(TI->Names) || II->getName() != BuiltinName)
875*700637cbSDimitry Andric     return not_intrinsic;
876*700637cbSDimitry Andric   return II->IntrinsicID;
877*700637cbSDimitry Andric }
878*700637cbSDimitry Andric #endif // GET_LLVM_INTRINSIC_FOR_{}_BUILTIN
879*700637cbSDimitry Andric 
880*700637cbSDimitry Andric )",
881*700637cbSDimitry Andric                 UpperCompilerName);
882*700637cbSDimitry Andric }
883*700637cbSDimitry Andric 
884*700637cbSDimitry Andric static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/true>>
885*700637cbSDimitry Andric     X("gen-intrinsic-enums", "Generate intrinsic enums");
886*700637cbSDimitry Andric 
887*700637cbSDimitry Andric static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/false>>
888*700637cbSDimitry Andric     Y("gen-intrinsic-impl", "Generate intrinsic implementation code");
889